diff --git a/CHANGELOG.md b/CHANGELOG.md index 44560a19d0e3..37a9ef98a9e5 100644 --- a/CHANGELOG.md +++ b/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) ` 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 diff --git a/client/context.go b/client/context.go index 90987355381b..690eec4ef4f5 100644 --- a/client/context.go +++ b/client/context.go @@ -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...) } diff --git a/client/keys/add.go b/client/keys/add.go index d9713fd2d57a..4480ad699853 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -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 != nil { + if err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk); err != nil { return err } - info, err := kb.SavePubKey(name, pk, algo.Name()) + k, err := kb.SaveOfflineKey(name, pk) 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 } diff --git a/client/keys/add_ledger_test.go b/client/keys/add_ledger_test.go index 69ccb32a4289..2b106615bcd4 100644 --- a/client/keys/add_ledger_test.go +++ b/client/keys/add_ledger_test.go @@ -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()) } }) } diff --git a/client/keys/add_test.go b/client/keys/add_test.go index 2108380588d3..1db737991114 100644 --- a/client/keys/add_test.go +++ b/client/keys/add_test.go @@ -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) } diff --git a/client/keys/delete.go b/client/keys/delete.go index e0921710141f..939ede062303 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -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 } diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go index e1687fc8d4b0..2250eac5ce9c 100644 --- a/client/keys/delete_test.go +++ b/client/keys/delete_test.go @@ -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{ diff --git a/client/keys/export_test.go b/client/keys/export_test.go index a63cf7f9b7f6..2dff05dd5ed7 100644 --- a/client/keys/export_test.go +++ b/client/keys/export_test.go @@ -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) diff --git a/client/keys/import_test.go b/client/keys/import_test.go index ac05ed567daa..37f4f3ce6bf9 100644 --- a/client/keys/import_test.go +++ b/client/keys/import_test.go @@ -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 }) diff --git a/client/keys/list.go b/client/keys/list.go index 9aae471db521..9156c0c2ac00 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -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 diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 17f8dd8e4f94..5d4ddb50d31f 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -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) diff --git a/client/keys/migrate.go b/client/keys/migrate.go index 321750d9e875..ff6cde2244a3 100644 --- a/client/keys/migrate.go +++ b/client/keys/migrate.go @@ -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 ", - 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 } diff --git a/client/keys/migrate_test.go b/client/keys/migrate_test.go index 32746291c882..48eefb168661 100644 --- a/client/keys/migrate_test.go +++ b/client/keys/migrate_test.go @@ -3,40 +3,152 @@ package keys import ( "context" "fmt" + "strings" "testing" - "github.com/cosmos/cosmos-sdk/client" - - "github.com/stretchr/testify/require" - - "github.com/otiai10/copy" - "github.com/stretchr/testify/assert" + design99keyring "github.com/99designs/keyring" + "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/client" "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) - ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) +type setter interface { + SetItem(item design99keyring.Item) error +} - require.NoError(t, copy.Copy("testdata", kbHome)) +type MigrateTestSuite struct { + suite.Suite - cmd := MigrateCommand() + 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) - mockIn, mockOut := testutil.ApplyMockIO(cmd) + + 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) 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)) } diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index c411612782e6..ea7f9638d9be 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -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" diff --git a/client/keys/rename.go b/client/keys/rename.go index 2c5f11263de0..18326c8d356a 100644 --- a/client/keys/rename.go +++ b/client/keys/rename.go @@ -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 } diff --git a/client/keys/rename_test.go b/client/keys/rename_test.go index 37d15ecba25e..cf2e859648db 100644 --- a/client/keys/rename_test.go +++ b/client/keys/rename_test.go @@ -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{ diff --git a/client/keys/show.go b/client/keys/show.go index 64ede012582f..d97b4a67d842 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -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() + ledgerItem := k.GetLedger() + if ledgerItem == nil { + return errors.New("unable to get ledger item") + } + + pk, err := k.GetPubKey() if err != nil { - return nil + return err } - return ledger.ShowAddress(*hdpath, info.GetPubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()) + 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 + return k, 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") + k, err = kb.KeyByAddress(accAddr) + return k, sdkerr.Wrap(err, "Invalid key") } func validateMultisigThreshold(k, nKeys int) error { diff --git a/client/keys/show_test.go b/client/keys/show_test.go index 60a70f3deb50..cd2157cba677 100644 --- a/client/keys/show_test.go +++ b/client/keys/show_test.go @@ -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") } diff --git a/client/keys/types.go b/client/keys/types.go index 129d26e29823..1df26ed2879d 100644 --- a/client/keys/types.go +++ b/client/keys/types.go @@ -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 { diff --git a/client/keys/utils.go b/client/keys/utils.go index 5e1daf1c4346..2e144eaf49b6 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -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) - -// 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...) -} +type bechKeyOutFn func(k *cryptokeyring.Record) (cryptokeyring.KeyOutput, error) -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)) } diff --git a/client/tx/tx.go b/client/tx/tx.go index d98eb7a4f003..23de49941594 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -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 diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 54bcc7ade649..8c3ed0ddf07a 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -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) diff --git a/crypto/armor_test.go b/crypto/armor_test.go index 8c7c0c5257d7..a2cab1105135 100644 --- a/crypto/armor_test.go +++ b/crypto/armor_test.go @@ -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) diff --git a/crypto/codec/proto.go b/crypto/codec/proto.go index 7f38dee61433..1340dab03de5 100644 --- a/crypto/codec/proto.go +++ b/crypto/codec/proto.go @@ -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) } diff --git a/crypto/hd/algo.go b/crypto/hd/algo.go index f934ad08aece..5f9965a24531 100644 --- a/crypto/hd/algo.go +++ b/crypto/hd/algo.go @@ -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" diff --git a/crypto/hd/fundraiser_test.go b/crypto/hd/fundraiser_test.go index 4afbfc5a9ced..d5c2b8f1ede8 100644 --- a/crypto/hd/fundraiser_test.go +++ b/crypto/hd/fundraiser_test.go @@ -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" diff --git a/crypto/hd/hd.pb.go b/crypto/hd/hd.pb.go new file mode 100644 index 000000000000..cbf26a3bae22 --- /dev/null +++ b/crypto/hd/hd.pb.go @@ -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") +) diff --git a/crypto/hd/hdpath.go b/crypto/hd/hdpath.go index 058ddcc45667..96056a99b53a 100644 --- a/crypto/hd/hdpath.go +++ b/crypto/hd/hdpath.go @@ -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 { diff --git a/crypto/hd/hdpath_test.go b/crypto/hd/hdpath_test.go index 8b1c40692c82..42abd023870a 100644 --- a/crypto/hd/hdpath_test.go +++ b/crypto/hd/hdpath_test.go @@ -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" ) diff --git a/crypto/keyring/codec.go b/crypto/keyring/codec.go index 558f377752d2..9b4c44039231 100644 --- a/crypto/keyring/codec.go +++ b/crypto/keyring/codec.go @@ -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) } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index 8619c9f48482..9939ac4380ac 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -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 + } + + key, err := k.GetPubKey() if err != nil { return "", err } - if bz == nil { - return "", fmt.Errorf("no key to export with name: %s", uid) + bz, err := ks.cdc.MarshalInterface(key) + if err != nil { + return "", err } - return crypto.ArmorPubKeyBytes(legacy.Cdc.MustMarshal(bz.GetPubKey()), string(bz.GetAlgo())), nil + 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") + switch { + case k.GetLocal() != nil: + priv, err := extractPrivKeyFromLocal(k.GetLocal()) + if err != nil { + return nil, nil, err } - priv, err = legacy.PrivKeyFromBytes([]byte(i.PrivKeyArmor)) + sig, err := priv.Sign(msg) if err != nil { return nil, nil, err } - case ledgerInfo: - return SignWithLedger(info, msg) + return sig, priv.PubKey(), nil - case offlineInfo, multiInfo: - return nil, info.GetPubKey(), errors.New("cannot sign with offline keys") - } + case k.GetLedger() != nil: + return SignWithLedger(k, msg) - sig, err := priv.Sign(msg) - if err != nil { - return nil, nil, err - } + // multi or offline record + default: + pub, err := k.GetPubKey() + if err != nil { + return nil, nil, err + } - return sig, priv.PubKey(), nil + return nil, pub, errors.New("cannot sign with offline keys") + } } 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 strings.Contains(key, addressSuffix) { + continue + } - if len(rawInfo.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key) - } + item, err := ks.db.Get(key) + if err != nil { + return nil, err + } - info, err := unmarshalInfo(rawInfo.Data) - if err != nil { - return nil, err - } + if len(item.Data) == 0 { + return nil, sdkerrors.ErrKeyNotFound.Wrap(key) + } - res = append(res, info) + 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) - } - if len(bs.Data) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, infoKey) + return nil, err } - 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 { diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go index cccfa20452bc..b57351ba947a 100644 --- a/crypto/keyring/keyring_ledger_test.go +++ b/crypto/keyring/keyring_ledger_test.go @@ -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()) } diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index c2a0df70a7d9..6fc968240b21 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -10,7 +10,10 @@ import ( bip39 "github.com/cosmos/go-bip39" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" @@ -29,35 +32,44 @@ func init() { crypto.BcryptSecurityParameter = 1 } +func getCodec() codec.Codec { + registry := codectypes.NewInterfaceRegistry() + cryptocodec.RegisterInterfaces(registry) + return codec.NewProtoCodec(registry) +} + func TestNewKeyring(t *testing.T) { dir := t.TempDir() mockIn := strings.NewReader("") + cdc := getCodec() - kr, err := New("cosmos", BackendFile, dir, mockIn) + kr, err := New("cosmos", BackendFile, dir, mockIn, cdc) require.NoError(t, err) - nilKr, err := New("cosmos", "fuzzy", dir, mockIn) + nilKr, err := New("cosmos", "fuzzy", dir, mockIn, cdc) require.Error(t, err) require.Nil(t, nilKr) require.Equal(t, "unknown keyring backend fuzzy", err.Error()) mockIn.Reset("password\npassword\n") - info, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + k, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - require.Equal(t, "foo", info.GetName()) + require.Equal(t, "foo", k.Name) } func TestKeyManagementKeyRing(t *testing.T) { - kb, err := New("keybasename", "test", t.TempDir(), nil) + cdc := getCodec() + kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) require.NoError(t, err) + require.NotNil(t, cdc) algo := hd.Secp256k1 n1, n2, n3 := "personal", "business", "other" // Check empty state - l, err := kb.List() - require.Nil(t, err) - require.Empty(t, l) + records, err := kb.List() + require.NoError(t, err) + require.Empty(t, records) _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.Error(t, err, "ed25519 keys are currently not supported by keybase") @@ -65,33 +77,44 @@ func TestKeyManagementKeyRing(t *testing.T) { // create some keys _, err = kb.Key(n1) require.Error(t, err) - i, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - + // save localKey with "n1`" + k, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) - require.Equal(t, n1, i.GetName()) - _, _, err = kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + require.Equal(t, n1, k.Name) + + // save localKey with "n2" + k1, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) + require.Equal(t, n2, k1.Name) - // we can get these keys - i2, err := kb.Key(n2) + k2, err := kb.Key(n2) require.NoError(t, err) _, err = kb.Key(n3) require.NotNil(t, err) - _, err = kb.KeyByAddress(accAddr(i2)) + addr, err := k2.GetAddress() require.NoError(t, err) - addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") + _, err = kb.KeyByAddress(addr) + require.NoError(t, err) + addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") require.NoError(t, err) _, err = kb.KeyByAddress(addr) - require.NotNil(t, err) + require.Error(t, err) // list shows them in order keyS, err := kb.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) // note these are in alphabetical order - require.Equal(t, n2, keyS[0].GetName()) - require.Equal(t, n1, keyS[1].GetName()) - require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) + require.Equal(t, n2, keyS[0].Name) + require.Equal(t, n1, keyS[1].Name) + + key1, err := k2.GetPubKey() + require.NoError(t, err) + require.NotNil(t, key1) + key2, err := keyS[0].GetPubKey() + require.NoError(t, err) + require.NotNil(t, key2) + require.Equal(t, key1, key2) // deleting a key removes it err = kb.Delete("bad name") @@ -108,10 +131,15 @@ func TestKeyManagementKeyRing(t *testing.T) { o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = kb.SavePubKey(o1, pub1, hd.Ed25519Type) + k3, err := kb.SaveOfflineKey(o1, pub1) require.Nil(t, err) - require.Equal(t, pub1, i.GetPubKey()) - require.Equal(t, o1, i.GetName()) + + key1, err = k3.GetPubKey() + require.NoError(t, err) + require.NotNil(t, key1) + require.Equal(t, pub1, key1) + + require.Equal(t, o1, k3.Name) keyS, err = kb.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) @@ -129,18 +157,19 @@ func TestKeyManagementKeyRing(t *testing.T) { func TestSignVerifyKeyRing(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) algo := hd.Secp256k1 n1, n2, n3 := "some dude", "a dudette", "dude-ish" // create two users and get their info - i1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + kr1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) - i2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + kr2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) // let's try to sign some messages @@ -150,20 +179,28 @@ func TestSignVerifyKeyRing(t *testing.T) { // try signing both data with both .. s11, pub1, err := kb.Sign(n1, d1) - require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) + require.NoError(t, err) + + key1, err := kr1.GetPubKey() + require.NoError(t, err) + require.NotNil(t, key1) + require.Equal(t, key1, pub1) s12, pub1, err := kb.Sign(n1, d2) require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) + require.Equal(t, key1, pub1) s21, pub2, err := kb.Sign(n2, d1) require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) + + key2, err := kr2.GetPubKey() + require.NoError(t, err) + require.NotNil(t, key2) + require.Equal(t, key2, pub2) s22, pub2, err := kb.Sign(n2, d2) require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) + require.Equal(t, key2, pub2) // let's try to validate and make sure it only works when everything is proper cases := []struct { @@ -173,15 +210,15 @@ func TestSignVerifyKeyRing(t *testing.T) { valid bool }{ // proper matches - {i1.GetPubKey(), d1, s11, true}, + {key1, d1, s11, true}, // change data, pubkey, or signature leads to fail - {i1.GetPubKey(), d2, s11, false}, - {i2.GetPubKey(), d1, s11, false}, - {i1.GetPubKey(), d1, s21, false}, + {key1, d2, s11, false}, + {key2, d1, s11, false}, + {key1, d1, s21, false}, // make sure other successes - {i1.GetPubKey(), d2, s12, true}, - {i2.GetPubKey(), d1, s21, true}, - {i2.GetPubKey(), d2, s22, true}, + {key1, d2, s12, true}, + {key2, d1, s21, true}, + {key2, d2, s22, true}, } for i, tc := range cases { @@ -198,7 +235,7 @@ func TestSignVerifyKeyRing(t *testing.T) { require.NoError(t, kb.ImportPubKey(n3, armor)) i3, err := kb.Key(n3) require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) + require.Equal(t, i3.Name, n3) _, _, err = kb.Sign(n3, d3) require.Error(t, err) @@ -206,17 +243,21 @@ func TestSignVerifyKeyRing(t *testing.T) { } func TestExportImportKeyRing(t *testing.T) { - kb, err := New("keybasename", "test", t.TempDir(), nil) + cdc := getCodec() + kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) require.NoError(t, err) - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + name := k.Name require.NoError(t, err) - require.Equal(t, info.GetName(), "john") + require.Equal(t, name, "john") john, err := kb.Key("john") require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - johnAddr := info.GetPubKey().Address() + require.Equal(t, name, "john") + key, err := k.GetPubKey() + require.NoError(t, err) + johnAddr := key.Address() armor, err := kb.ExportPrivKeyArmor("john", "apassphrase") require.NoError(t, err) @@ -229,29 +270,44 @@ func TestExportImportKeyRing(t *testing.T) { john2, err := kb.Key("john2") require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), johnAddr) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetAddress(), john2.GetAddress()) - require.Equal(t, john.GetAlgo(), john2.GetAlgo()) - require.Equal(t, john.GetPubKey(), john2.GetPubKey()) - require.Equal(t, john.GetType(), john2.GetType()) + require.Equal(t, key.Address(), johnAddr) + require.Equal(t, john.Name, "john") + + addr, err := john.GetAddress() + require.NoError(t, err) + addr2, err := john2.GetAddress() + require.NoError(t, err) + require.Equal(t, addr, addr2) + + key, err = john.GetPubKey() + require.NoError(t, err) + key2, err := john2.GetPubKey() + require.NoError(t, err) + + require.True(t, key.Equals(key2)) } func TestExportImportPubKeyKeyRing(t *testing.T) { - kb, err := New("keybasename", "test", t.TempDir(), nil) + cdc := getCodec() + kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) require.NoError(t, err) algo := hd.Secp256k1 // CreateMnemonic a private-public key pair and ensure consistency - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) - require.NotEqual(t, info, "") - require.Equal(t, info.GetName(), "john") - addr := info.GetPubKey().Address() + require.NotNil(t, k) + require.Equal(t, k.Name, "john") + key, err := k.GetPubKey() + require.NoError(t, err) + addr := key.Address() john, err := kb.Key("john") require.NoError(t, err) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetPubKey().Address(), addr) + require.Equal(t, john.Name, "john") + + key, err = john.GetPubKey() + require.NoError(t, err) + require.Equal(t, key.Address(), addr) // Export the public key only armor, err := kb.ExportPubKeyArmor("john") @@ -266,9 +322,11 @@ func TestExportImportPubKeyKeyRing(t *testing.T) { // Ensure consistency john2, err := kb.Key("john-pubkey-only") require.NoError(t, err) + key2, err := john2.GetPubKey() + require.NoError(t, err) // Compare the public keys - require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) + require.True(t, key.Equals(key2)) // Ensure keys cannot be overwritten err = kb.ImportPubKey("john-pubkey-only", armor) @@ -277,8 +335,9 @@ func TestExportImportPubKeyKeyRing(t *testing.T) { func TestAdvancedKeyManagementKeyRing(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) algo := hd.Secp256k1 @@ -312,18 +371,21 @@ func TestAdvancedKeyManagementKeyRing(t *testing.T) { func TestSeedPhraseKeyRing(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) algo := hd.Secp256k1 n1, n2 := "lost-key", "found-again" // make sure key works with initial password - info, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + k, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) - require.Equal(t, n1, info.GetName()) + require.Equal(t, n1, k.Name) require.NotEmpty(t, mnemonic) + key, err := k.GetPubKey() + require.NoError(t, err) // now, let us delete this key err = kb.Delete(n1) @@ -332,17 +394,20 @@ func TestSeedPhraseKeyRing(t *testing.T) { require.NotNil(t, err) // let us re-create it from the mnemonic-phrase - params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - hdPath := params.String() - newInfo, err := kb.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1) + hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String() + k1, err := kb.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1) require.NoError(t, err) - require.Equal(t, n2, newInfo.GetName()) - require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) - require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) + require.Equal(t, n2, k1.Name) + newKey, err := k1.GetPubKey() + require.NoError(t, err) + + require.Equal(t, key.Address(), newKey.Address()) + require.Equal(t, key, newKey) } func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { - kb, err := New("keybasename", "test", t.TempDir(), nil) + cdc := getCodec() + kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) require.NoError(t, err) _, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) @@ -367,18 +432,20 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { // try export non existing key _, err = kb.ExportPrivKeyArmor("john3", "wrongpassword") - require.EqualError(t, err, "john3.info: key not found") + require.EqualError(t, err, "john3: key not found") } func TestInMemoryLanguage(t *testing.T) { - kb := NewInMemory() + cdc := getCodec() + kb := NewInMemory(cdc) _, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.Error(t, err) require.Equal(t, "unsupported language: only english is supported", err.Error()) } func TestInMemoryCreateMultisig(t *testing.T) { - kb, err := New("keybasename", "memory", "", nil) + cdc := getCodec() + kb, err := New("keybasename", "memory", "", nil, cdc) require.NoError(t, err) multi := multisig.NewLegacyAminoPubKey( 1, []types.PubKey{ @@ -390,7 +457,8 @@ func TestInMemoryCreateMultisig(t *testing.T) { } func TestInMemoryCreateAccountInvalidMnemonic(t *testing.T) { - kb := NewInMemory() + cdc := getCodec() + kb := NewInMemory(cdc) _, err := kb.NewAccount( "some_account", "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", @@ -402,14 +470,15 @@ func TestInMemoryCreateAccountInvalidMnemonic(t *testing.T) { // TestInMemoryKeyManagement makes sure we can manipulate these keys well func TestInMemoryKeyManagement(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) algo := hd.Secp256k1 n1, n2, n3 := "personal", "business", "other" // Check empty state l, err := cstore.List() - require.Nil(t, err) + require.NoError(t, err) require.Empty(t, l) _, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) @@ -418,21 +487,23 @@ func TestInMemoryKeyManagement(t *testing.T) { // create some keys _, err = cstore.Key(n1) require.Error(t, err) - i, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + k, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) - require.Equal(t, n1, i.GetName()) + require.Equal(t, n1, k.Name) _, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.NoError(t, err) // we can get these keys - i2, err := cstore.Key(n2) + k2, err := cstore.Key(n2) require.NoError(t, err) _, err = cstore.Key(n3) require.NotNil(t, err) - _, err = cstore.KeyByAddress(accAddr(i2)) + addr, err := accAddr(k2) require.NoError(t, err) - addr, err := sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") + _, err = cstore.KeyByAddress(addr) + require.NoError(t, err) + addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") require.NoError(t, err) _, err = cstore.KeyByAddress(addr) require.NotNil(t, err) @@ -442,9 +513,15 @@ func TestInMemoryKeyManagement(t *testing.T) { require.NoError(t, err) require.Equal(t, 2, len(keyS)) // note these are in alphabetical order - require.Equal(t, n2, keyS[0].GetName()) - require.Equal(t, n1, keyS[1].GetName()) - require.Equal(t, i2.GetPubKey(), keyS[0].GetPubKey()) + require.Equal(t, n2, keyS[0].Name) + require.Equal(t, n1, keyS[1].Name) + + key1, err := k2.GetPubKey() + require.NoError(t, err) + key2, err := keyS[0].GetPubKey() + require.NoError(t, err) + + require.True(t, key1.Equals(key2)) // deleting a key removes it err = cstore.Delete("bad name") @@ -461,12 +538,15 @@ func TestInMemoryKeyManagement(t *testing.T) { o1 := "offline" priv1 := ed25519.GenPrivKey() pub1 := priv1.PubKey() - i, err = cstore.SavePubKey(o1, pub1, hd.Ed25519Type) + k, err = cstore.SaveOfflineKey(o1, pub1) require.Nil(t, err) - require.Equal(t, pub1, i.GetPubKey()) - require.Equal(t, o1, i.GetName()) - iOffline := i.(*offlineInfo) - require.Equal(t, hd.Ed25519Type, iOffline.GetAlgo()) + + key, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub1, key) + + require.Equal(t, o1, k.Name) + require.NotNil(t, k.GetOffline()) keyS, err = cstore.List() require.NoError(t, err) require.Equal(t, 2, len(keyS)) @@ -486,16 +566,17 @@ func TestInMemoryKeyManagement(t *testing.T) { // TestInMemorySignVerify does some detailed checks on how we sign and validate // signatures func TestInMemorySignVerify(t *testing.T) { - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) algo := hd.Secp256k1 n1, n2, n3 := "some dude", "a dudette", "dude-ish" // create two users and get their info - i1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + kr1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) - i2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + kr2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err) // let's try to sign some messages @@ -506,19 +587,23 @@ func TestInMemorySignVerify(t *testing.T) { // try signing both data with both .. s11, pub1, err := cstore.Sign(n1, d1) require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) + key1, err := kr1.GetPubKey() + require.NoError(t, err) + require.Equal(t, key1, pub1) s12, pub1, err := cstore.Sign(n1, d2) require.Nil(t, err) - require.Equal(t, i1.GetPubKey(), pub1) + require.Equal(t, key1, pub1) s21, pub2, err := cstore.Sign(n2, d1) require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) + key2, err := kr2.GetPubKey() + require.NoError(t, err) + require.Equal(t, key2, pub2) s22, pub2, err := cstore.Sign(n2, d2) require.Nil(t, err) - require.Equal(t, i2.GetPubKey(), pub2) + require.Equal(t, key2, pub2) // let's try to validate and make sure it only works when everything is proper cases := []struct { @@ -528,15 +613,15 @@ func TestInMemorySignVerify(t *testing.T) { valid bool }{ // proper matches - {i1.GetPubKey(), d1, s11, true}, + {key1, d1, s11, true}, // change data, pubkey, or signature leads to fail - {i1.GetPubKey(), d2, s11, false}, - {i2.GetPubKey(), d1, s11, false}, - {i1.GetPubKey(), d1, s21, false}, + {key1, d2, s11, false}, + {key2, d1, s11, false}, + {key1, d1, s21, false}, // make sure other successes - {i1.GetPubKey(), d2, s12, true}, - {i2.GetPubKey(), d1, s21, true}, - {i2.GetPubKey(), d2, s22, true}, + {key1, d2, s12, true}, + {key2, d1, s21, true}, + {key2, d2, s22, true}, } for i, tc := range cases { @@ -553,7 +638,7 @@ func TestInMemorySignVerify(t *testing.T) { require.NoError(t, err) i3, err := cstore.Key(n3) require.NoError(t, err) - require.Equal(t, i3.GetName(), n3) + require.Equal(t, i3.Name, n3) // Now try to sign data with a secret-less key _, _, err = cstore.Sign(n3, d3) @@ -564,16 +649,19 @@ func TestInMemorySignVerify(t *testing.T) { // TestInMemoryExportImport tests exporting and importing func TestInMemoryExportImport(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) - info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + k, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - require.Equal(t, info.GetName(), "john") + require.Equal(t, k.Name, "john") john, err := cstore.Key("john") require.NoError(t, err) - require.Equal(t, info.GetName(), "john") - johnAddr := info.GetPubKey().Address() + require.Equal(t, k.Name, "john") + johnKey, err := k.GetPubKey() + require.NoError(t, err) + johnAddr := johnKey.Address() armor, err := cstore.ExportPubKeyArmor("john") require.NoError(t, err) @@ -586,19 +674,27 @@ func TestInMemoryExportImport(t *testing.T) { john2, err := cstore.Key("john2") require.NoError(t, err) - require.Equal(t, john.GetPubKey().Address(), johnAddr) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetAddress(), john2.GetAddress()) - require.Equal(t, john.GetAlgo(), john2.GetAlgo()) - require.Equal(t, john.GetPubKey(), john2.GetPubKey()) + require.Equal(t, johnKey.Address(), johnAddr) + require.Equal(t, john.Name, "john") + + johnSdkAddress, err := john.GetAddress() + require.NoError(t, err) + john2SdkAddress, err := john2.GetAddress() + require.NoError(t, err) + require.Equal(t, johnSdkAddress, john2SdkAddress) + john2Key, err := john2.GetPubKey() + require.NoError(t, err) + + require.True(t, johnKey.Equals(john2Key)) } func TestInMemoryExportImportPrivKey(t *testing.T) { - kb := NewInMemory() + cdc := getCodec() + kb := NewInMemory(cdc) - info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - require.Equal(t, info.GetName(), "john") + require.Equal(t, k.Name, "john") priv1, err := kb.Key("john") require.NoError(t, err) @@ -616,23 +712,32 @@ func TestInMemoryExportImportPrivKey(t *testing.T) { // ensure old and new keys match priv2, err := kb.Key("john") require.NoError(t, err) - require.True(t, priv1.GetPubKey().Equals(priv2.GetPubKey())) + key1, err := priv1.GetPubKey() + require.NoError(t, err) + key2, err := priv2.GetPubKey() + require.NoError(t, err) + require.True(t, key1.Equals(key2)) } func TestInMemoryExportImportPubKey(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) // CreateMnemonic a private-public key pair and ensure consistency - info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.Nil(t, err) - require.NotEqual(t, info, "") - require.Equal(t, info.GetName(), "john") - addr := info.GetPubKey().Address() + k, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.NotNil(t, k) + require.Equal(t, k.Name, "john") + key, err := k.GetPubKey() + require.NoError(t, err) + addr := key.Address() john, err := cstore.Key("john") require.NoError(t, err) - require.Equal(t, john.GetName(), "john") - require.Equal(t, john.GetPubKey().Address(), addr) + require.Equal(t, john.Name, "john") + johnKey, err := john.GetPubKey() + require.NoError(t, err) + require.Equal(t, johnKey.Address(), addr) // Export the public key only armor, err := cstore.ExportPubKeyArmor("john") @@ -647,7 +752,9 @@ func TestInMemoryExportImportPubKey(t *testing.T) { john2, err := cstore.Key("john-pubkey-only") require.NoError(t, err) // Compare the public keys - require.True(t, john.GetPubKey().Equals(john2.GetPubKey())) + john2Key, err := john2.GetPubKey() + require.NoError(t, err) + require.True(t, johnKey.Equals(john2Key)) // Ensure keys cannot be overwritten err = cstore.ImportPubKey("john-pubkey-only", armor) @@ -657,7 +764,8 @@ func TestInMemoryExportImportPubKey(t *testing.T) { // TestInMemoryAdvancedKeyManagement verifies update, import, export functionality func TestInMemoryAdvancedKeyManagement(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) algo := hd.Secp256k1 n1, n2 := "old-name", "new name" @@ -692,15 +800,16 @@ func TestInMemoryAdvancedKeyManagement(t *testing.T) { // TestInMemorySeedPhrase verifies restoring from a seed phrase func TestInMemorySeedPhrase(t *testing.T) { // make the storage with reasonable defaults - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) algo := hd.Secp256k1 n1, n2 := "lost-key", "found-again" // make sure key works with initial password - info, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + k, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) require.Nil(t, err, "%+v", err) - require.Equal(t, n1, info.GetName()) + require.Equal(t, n1, k.Name) require.NotEmpty(t, mnemonic) // now, let us delete this key @@ -710,17 +819,21 @@ func TestInMemorySeedPhrase(t *testing.T) { require.NotNil(t, err) // let us re-create it from the mnemonic-phrase - params := *hd.NewFundraiserParams(0, sdk.CoinType, 0) - hdPath := params.String() - newInfo, err := cstore.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, algo) + hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String() + k1, err := cstore.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, algo) + require.NoError(t, err) + require.Equal(t, n2, k1.Name) + key, err := k.GetPubKey() require.NoError(t, err) - require.Equal(t, n2, newInfo.GetName()) - require.Equal(t, info.GetPubKey().Address(), newInfo.GetPubKey().Address()) - require.Equal(t, info.GetPubKey(), newInfo.GetPubKey()) + key1, err := k1.GetPubKey() + require.NoError(t, err) + require.Equal(t, key.Address(), key1.Address()) + require.Equal(t, key, key1) } func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) { - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) // Given we create a mnemonic @@ -740,7 +853,8 @@ func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) { func ExampleNew() { // Select the encryption and storage for your cryptostore - cstore := NewInMemory() + cdc := getCodec() + cstore := NewInMemory(cdc) sec := hd.Secp256k1 @@ -751,13 +865,13 @@ func ExampleNew() { fmt.Println(err) } else { // return info here just like in List - fmt.Println(bob.GetName()) + fmt.Println(bob.Name) } _, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec) _, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec) - info, _ := cstore.List() - for _, i := range info { - fmt.Println(i.GetName()) + records, _ := cstore.List() + for _, k := range records { + fmt.Println(k.Name) } // We need to use passphrase to generate a signature @@ -768,12 +882,14 @@ func ExampleNew() { } // and we can validate the signature with publicly available info - binfo, _ := cstore.Key("Bob") - if !binfo.GetPubKey().Equals(bob.GetPubKey()) { + bRecord, _ := cstore.Key("Bob") + key, _ := bRecord.GetPubKey() + bobKey, _ := bob.GetPubKey() + if !key.Equals(bobKey) { fmt.Println("Get and Create return different keys") } - if pub.Equals(binfo.GetPubKey()) { + if pub.Equals(key) { fmt.Println("signed by Bob") } if !pub.VerifySignature(tx, sig) { @@ -790,39 +906,41 @@ func ExampleNew() { func TestAltKeyring_List(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) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Empty(t, list) // Fails on creating unsupported pubKeyType - _, _, err = keyring.NewMnemonic("failing", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) + _, _, err = kr.NewMnemonic("failing", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) // Create 3 keys uid1, uid2, uid3 := "Zkey", "Bkey", "Rkey" - _, _, err = keyring.NewMnemonic(uid1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - _, _, err = keyring.NewMnemonic(uid2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - _, _, err = keyring.NewMnemonic(uid3, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid3, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - list, err = keyring.List() + list, err = kr.List() require.NoError(t, err) require.Len(t, list, 3) // Check they are in alphabetical order - require.Equal(t, uid2, list[0].GetName()) - require.Equal(t, uid3, list[1].GetName()) - require.Equal(t, uid1, list[2].GetName()) + require.Equal(t, uid2, list[0].Name) + require.Equal(t, uid3, list[1].Name) + require.Equal(t, uid1, list[2].Name) } func TestAltKeyring_NewAccount(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) entropy, err := bip39.NewEntropy(defaultEntropySize) @@ -834,90 +952,99 @@ func TestAltKeyring_NewAccount(t *testing.T) { uid := "newUid" // Fails on creating unsupported pubKeyType - _, err = keyring.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, notSupportedAlgo{}) + _, err = kr.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, notSupportedAlgo{}) require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) - info, err := keyring.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1) + k, err := kr.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1) require.NoError(t, err) - require.Equal(t, uid, info.GetName()) + require.Equal(t, uid, k.Name) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Len(t, list, 1) } func TestAltKeyring_Get(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - key, err := keyring.Key(uid) + key, err := kr.Key(uid) require.NoError(t, err) - requireEqualInfo(t, mnemonic, key) + requireEqualRenamedKey(t, mnemonic, key, true) } func TestAltKeyring_KeyByAddress(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - key, err := keyring.KeyByAddress(mnemonic.GetAddress()) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + key, err := kr.KeyByAddress(addr) require.NoError(t, err) - requireEqualInfo(t, key, mnemonic) + requireEqualRenamedKey(t, key, mnemonic, true) } func TestAltKeyring_Delete(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := someKey - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Len(t, list, 1) - err = keyring.Delete(uid) + err = kr.Delete(uid) require.NoError(t, err) - list, err = keyring.List() + list, err = kr.List() require.NoError(t, err) require.Empty(t, list) } func TestAltKeyring_DeleteByAddress(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := someKey - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Len(t, list, 1) - err = keyring.DeleteByAddress(mnemonic.GetAddress()) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + err = kr.DeleteByAddress(addr) require.NoError(t, err) - list, err = keyring.List() + list, err = kr.List() require.NoError(t, err) require.Empty(t, list) } -func TestAltKeyring_SavePubKey(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) +func TestAltKeyring_SaveOfflineKey(t *testing.T) { + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Empty(t, list) @@ -925,184 +1052,205 @@ func TestAltKeyring_SavePubKey(t *testing.T) { priv := ed25519.GenPrivKey() pub := priv.PubKey() - info, err := keyring.SavePubKey(key, pub, hd.Secp256k1.Name()) + k, err := kr.SaveOfflineKey(key, pub) require.Nil(t, err) - require.Equal(t, pub, info.GetPubKey()) - require.Equal(t, key, info.GetName()) - require.Equal(t, hd.Secp256k1.Name(), info.GetAlgo()) + pubKey, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub, pubKey) + require.Equal(t, key, k.Name) - list, err = keyring.List() + list, err = kr.List() require.NoError(t, err) - require.Equal(t, 1, len(list)) + require.Len(t, list, 1) } func TestAltKeyring_SaveMultisig(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) - mnemonic1, _, err := keyring.NewMnemonic("key1", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic1, _, err := kr.NewMnemonic("key1", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - mnemonic2, _, err := keyring.NewMnemonic("key2", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic2, _, err := kr.NewMnemonic("key2", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) key := "multi" + key1, err := mnemonic1.GetPubKey() + require.NoError(t, err) + key2, err := mnemonic2.GetPubKey() + require.NoError(t, err) pub := multisig.NewLegacyAminoPubKey( 2, []types.PubKey{ - &secp256k1.PubKey{Key: mnemonic1.GetPubKey().Bytes()}, - &secp256k1.PubKey{Key: mnemonic2.GetPubKey().Bytes()}, + &secp256k1.PubKey{Key: key1.Bytes()}, + &secp256k1.PubKey{Key: key2.Bytes()}, }, ) - info, err := keyring.SaveMultisig(key, pub) + k, err := kr.SaveMultisig(key, pub) require.Nil(t, err) - require.Equal(t, pub, info.GetPubKey()) - require.Equal(t, key, info.GetName()) + infoKey, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub, infoKey) + require.Equal(t, key, k.Name) - list, err := keyring.List() + list, err := kr.List() require.NoError(t, err) require.Len(t, list, 3) } func TestAltKeyring_Sign(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := "jack" - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) msg := []byte("some message") - sign, key, err := keyring.Sign(uid, msg) + sign, key, err := kr.Sign(uid, msg) require.NoError(t, err) require.True(t, key.VerifySignature(msg, sign)) } func TestAltKeyring_SignByAddress(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := "jack" - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) msg := []byte("some message") - sign, key, err := keyring.SignByAddress(mnemonic.GetAddress(), msg) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + sign, key, err := kr.SignByAddress(addr, msg) require.NoError(t, err) require.True(t, key.VerifySignature(msg, sign)) } func TestAltKeyring_ImportExportPrivKey(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) passphrase := "somePass" - armor, err := keyring.ExportPrivKeyArmor(uid, passphrase) + armor, err := kr.ExportPrivKeyArmor(uid, passphrase) require.NoError(t, err) - err = keyring.Delete(uid) + err = kr.Delete(uid) require.NoError(t, err) newUID := otherID // Should fail importing with wrong password - err = keyring.ImportPrivKey(newUID, armor, "wrongPass") + err = kr.ImportPrivKey(newUID, armor, "wrongPass") require.EqualError(t, err, "failed to decrypt private key: ciphertext decryption failed") - err = keyring.ImportPrivKey(newUID, armor, passphrase) + err = kr.ImportPrivKey(newUID, armor, passphrase) require.NoError(t, err) // Should fail importing private key on existing key. - err = keyring.ImportPrivKey(newUID, armor, passphrase) + err = kr.ImportPrivKey(newUID, armor, passphrase) require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } func TestAltKeyring_ImportExportPrivKey_ByAddress(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := theID - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) passphrase := "somePass" - armor, err := keyring.ExportPrivKeyArmorByAddress(mnemonic.GetAddress(), passphrase) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + armor, err := kr.ExportPrivKeyArmorByAddress(addr, passphrase) require.NoError(t, err) - err = keyring.Delete(uid) + err = kr.Delete(uid) require.NoError(t, err) newUID := otherID // Should fail importing with wrong password - err = keyring.ImportPrivKey(newUID, armor, "wrongPass") + err = kr.ImportPrivKey(newUID, armor, "wrongPass") require.EqualError(t, err, "failed to decrypt private key: ciphertext decryption failed") - err = keyring.ImportPrivKey(newUID, armor, passphrase) + err = kr.ImportPrivKey(newUID, armor, passphrase) require.NoError(t, err) // Should fail importing private key on existing key. - err = keyring.ImportPrivKey(newUID, armor, passphrase) + err = kr.ImportPrivKey(newUID, armor, passphrase) require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } func TestAltKeyring_ImportExportPubKey(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - armor, err := keyring.ExportPubKeyArmor(uid) + armor, err := kr.ExportPubKeyArmor(uid) require.NoError(t, err) - err = keyring.Delete(uid) + err = kr.Delete(uid) require.NoError(t, err) newUID := otherID - err = keyring.ImportPubKey(newUID, armor) + err = kr.ImportPubKey(newUID, armor) require.NoError(t, err) // Should fail importing private key on existing key. - err = keyring.ImportPubKey(newUID, armor) + err = kr.ImportPubKey(newUID, armor) require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := theID - mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - armor, err := keyring.ExportPubKeyArmorByAddress(mnemonic.GetAddress()) + addr, err := mnemonic.GetAddress() require.NoError(t, err) - err = keyring.Delete(uid) + armor, err := kr.ExportPubKeyArmorByAddress(addr) + require.NoError(t, err) + err = kr.Delete(uid) require.NoError(t, err) newUID := otherID - err = keyring.ImportPubKey(newUID, armor) + err = kr.ImportPubKey(newUID, armor) require.NoError(t, err) // Should fail importing private key on existing key. - err = keyring.ImportPubKey(newUID, armor) + err = kr.ImportPubKey(newUID, armor) require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID)) } func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) uid := theID - _, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - unsafeKeyring := NewUnsafe(keyring) + unsafeKeyring := NewUnsafe(kr) privKey, err := unsafeKeyring.UnsafeExportPrivKeyHex(uid) require.NoError(t, err) @@ -1117,19 +1265,20 @@ func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { } func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { - keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil) + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) // should fail when using unsupported signing algorythm. - _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) + _, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.EqualError(t, err, "unsupported signing algo") // but works with default signing algo. - _, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + _, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) // but we can create a new keybase with our provided algos. - keyring2, err := New(t.Name(), BackendTest, t.TempDir(), nil, func(options *Options) { + kr2, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc, func(options *Options) { options.SupportedAlgos = SigningAlgoList{ notSupportedAlgo{}, } @@ -1137,7 +1286,7 @@ func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { require.NoError(t, err) // now this new keyring does not fail when signing with provided algo - _, _, err = keyring2.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) + _, _, err = kr2.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) require.NoError(t, err) } @@ -1162,13 +1311,13 @@ func TestRenameKey(t *testing.T) { name: "rename a key", run: func(kr Keyring) { oldKeyUID, newKeyUID := "old", "new" - oldKeyInfo := newKeyInfo(t, kr, oldKeyUID) + oldKeyRecord := newKeyRecord(t, kr, oldKeyUID) err := kr.Rename(oldKeyUID, newKeyUID) // rename from "old" to "new" require.NoError(t, err) - newInfo, err := kr.Key(newKeyUID) // new key should be in keyring + newRecord, err := kr.Key(newKeyUID) // new key should be in keyring require.NoError(t, err) - requireEqualRenamedKey(t, newInfo, oldKeyInfo) // oldinfo and newinfo should be the same - oldKeyInfo, err = kr.Key(oldKeyUID) // old key should be gone from keyring + requireEqualRenamedKey(t, newRecord, oldKeyRecord, false) // oldKeyRecord and newRecord should be the same except name + oldKeyRecord, err = kr.Key(oldKeyUID) // old key should be gone from keyring require.Error(t, err) }, }, @@ -1183,8 +1332,8 @@ func TestRenameKey(t *testing.T) { name: "cant rename a key to an already existing key name", run: func(kr Keyring) { key1, key2 := "existingKey", "existingKey2" // create 2 keys - newKeyInfo(t, kr, key1) - newKeyInfo(t, kr, key2) + newKeyRecord(t, kr, key1) + newKeyRecord(t, kr, key2) err := kr.Rename(key2, key1) require.Equal(t, fmt.Errorf("rename failed: %s already exists in the keyring", key1), err) assertKeysExist(t, kr, key1, key2) // keys should still exist after failed rename @@ -1194,7 +1343,7 @@ func TestRenameKey(t *testing.T) { name: "cant rename key to itself", run: func(kr Keyring) { keyName := "keyName" - newKeyInfo(t, kr, keyName) + newKeyRecord(t, kr, keyName) err := kr.Rename(keyName, keyName) require.Equal(t, fmt.Errorf("rename failed: %s already exists in the keyring", keyName), err) assertKeysExist(t, kr, keyName) @@ -1211,32 +1360,35 @@ func TestRenameKey(t *testing.T) { } } -func requireEqualRenamedKey(t *testing.T, newKey, oldKey Info) { - require.NotEqual(t, newKey.GetName(), oldKey.GetName()) - require.Equal(t, newKey.GetAddress(), oldKey.GetAddress()) - require.Equal(t, newKey.GetPubKey(), oldKey.GetPubKey()) - require.Equal(t, newKey.GetAlgo(), oldKey.GetAlgo()) - require.Equal(t, newKey.GetType(), oldKey.GetType()) -} +func requireEqualRenamedKey(t *testing.T, key *Record, mnemonic *Record, nameMatch bool) { + if nameMatch { + require.Equal(t, key.Name, mnemonic.Name) + } + keyAddr, err := key.GetAddress() + require.NoError(t, err) + mnemonicAddr, err := mnemonic.GetAddress() + require.NoError(t, err) + require.Equal(t, keyAddr, mnemonicAddr) -func requireEqualInfo(t *testing.T, key Info, mnemonic Info) { - require.Equal(t, key.GetName(), mnemonic.GetName()) - require.Equal(t, key.GetAddress(), mnemonic.GetAddress()) - require.Equal(t, key.GetPubKey(), mnemonic.GetPubKey()) - require.Equal(t, key.GetAlgo(), mnemonic.GetAlgo()) + key1, err := key.GetPubKey() + require.NoError(t, err) + key2, err := mnemonic.GetPubKey() + require.NoError(t, err) + require.Equal(t, key1, key2) require.Equal(t, key.GetType(), mnemonic.GetType()) } func newKeyring(t *testing.T, name string) Keyring { - kr, err := New(name, "test", t.TempDir(), nil) + cdc := getCodec() + kr, err := New(name, "test", t.TempDir(), nil, cdc) require.NoError(t, err) return kr } -func newKeyInfo(t *testing.T, kr Keyring, name string) Info { - keyInfo, _, err := kr.NewMnemonic(name, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) +func newKeyRecord(t *testing.T, kr Keyring, name string) *Record { + k, _, err := kr.NewMnemonic(name, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - return keyInfo + return k } func assertKeysExist(t *testing.T, kr Keyring, names ...string) { @@ -1246,4 +1398,4 @@ func assertKeysExist(t *testing.T, kr Keyring, names ...string) { } } -func accAddr(info Info) sdk.AccAddress { return info.GetAddress() } +func accAddr(k *Record) (sdk.AccAddress, error) { return k.GetAddress() } diff --git a/crypto/keyring/legacy.go b/crypto/keyring/legacy.go deleted file mode 100644 index 00ca8bfcc3df..000000000000 --- a/crypto/keyring/legacy.go +++ /dev/null @@ -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 { -} diff --git a/crypto/keyring/info.go b/crypto/keyring/legacy_info.go similarity index 60% rename from crypto/keyring/info.go rename to crypto/keyring/legacy_info.go index 2b183317c971..0480fa5eb262 100644 --- a/crypto/keyring/info.go +++ b/crypto/keyring/legacy_info.go @@ -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) + } +} diff --git a/crypto/keyring/legacy_test.go b/crypto/keyring/legacy_test.go deleted file mode 100644 index d1b0dbf3e682..000000000000 --- a/crypto/keyring/legacy_test.go +++ /dev/null @@ -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) -} diff --git a/crypto/keyring/migration_test.go b/crypto/keyring/migration_test.go new file mode 100644 index 000000000000..cfe55bd657a9 --- /dev/null +++ b/crypto/keyring/migration_test.go @@ -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, + } +} diff --git a/crypto/keyring/output.go b/crypto/keyring/output.go index 91588e31379f..87bec26ad84e 100644 --- a/crypto/keyring/output.go +++ b/crypto/keyring/output.go @@ -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 } diff --git a/crypto/keyring/output_test.go b/crypto/keyring/output_test.go index 8f28e8cd1f9f..c7a2e4d65945 100644 --- a/crypto/keyring/output_test.go +++ b/crypto/keyring/output_test.go @@ -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)) } diff --git a/crypto/keyring/record.go b/crypto/keyring/record.go new file mode 100644 index 000000000000..acc84f6490b1 --- /dev/null +++ b/crypto/keyring/record.go @@ -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 +} diff --git a/crypto/keyring/record.pb.go b/crypto/keyring/record.pb.go new file mode 100644 index 000000000000..c94e1ce0faa8 --- /dev/null +++ b/crypto/keyring/record.pb.go @@ -0,0 +1,1377 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/crypto/keyring/v1/record.proto + +package keyring + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + hd "github.com/cosmos/cosmos-sdk/crypto/hd" + _ "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 + +// Record is used for representing a key in the keyring. +type Record struct { + // name represents a name of Record + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // pub_key represents a public key in any format + PubKey *types.Any `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` + // Record contains one of the following items + // + // Types that are valid to be assigned to Item: + // *Record_Local_ + // *Record_Ledger_ + // *Record_Multi_ + // *Record_Offline_ + Item isRecord_Item `protobuf_oneof:"item"` +} + +func (m *Record) Reset() { *m = Record{} } +func (m *Record) String() string { return proto.CompactTextString(m) } +func (*Record) ProtoMessage() {} +func (*Record) Descriptor() ([]byte, []int) { + return fileDescriptor_36d640103edea005, []int{0} +} +func (m *Record) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Record) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Record.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 *Record) XXX_Merge(src proto.Message) { + xxx_messageInfo_Record.Merge(m, src) +} +func (m *Record) XXX_Size() int { + return m.Size() +} +func (m *Record) XXX_DiscardUnknown() { + xxx_messageInfo_Record.DiscardUnknown(m) +} + +var xxx_messageInfo_Record proto.InternalMessageInfo + +type isRecord_Item interface { + isRecord_Item() + MarshalTo([]byte) (int, error) + Size() int +} + +type Record_Local_ struct { + Local *Record_Local `protobuf:"bytes,3,opt,name=local,proto3,oneof" json:"local,omitempty"` +} +type Record_Ledger_ struct { + Ledger *Record_Ledger `protobuf:"bytes,4,opt,name=ledger,proto3,oneof" json:"ledger,omitempty"` +} +type Record_Multi_ struct { + Multi *Record_Multi `protobuf:"bytes,5,opt,name=multi,proto3,oneof" json:"multi,omitempty"` +} +type Record_Offline_ struct { + Offline *Record_Offline `protobuf:"bytes,6,opt,name=offline,proto3,oneof" json:"offline,omitempty"` +} + +func (*Record_Local_) isRecord_Item() {} +func (*Record_Ledger_) isRecord_Item() {} +func (*Record_Multi_) isRecord_Item() {} +func (*Record_Offline_) isRecord_Item() {} + +func (m *Record) GetItem() isRecord_Item { + if m != nil { + return m.Item + } + return nil +} + +func (m *Record) GetLocal() *Record_Local { + if x, ok := m.GetItem().(*Record_Local_); ok { + return x.Local + } + return nil +} + +func (m *Record) GetLedger() *Record_Ledger { + if x, ok := m.GetItem().(*Record_Ledger_); ok { + return x.Ledger + } + return nil +} + +func (m *Record) GetMulti() *Record_Multi { + if x, ok := m.GetItem().(*Record_Multi_); ok { + return x.Multi + } + return nil +} + +func (m *Record) GetOffline() *Record_Offline { + if x, ok := m.GetItem().(*Record_Offline_); ok { + return x.Offline + } + return nil +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*Record) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*Record_Local_)(nil), + (*Record_Ledger_)(nil), + (*Record_Multi_)(nil), + (*Record_Offline_)(nil), + } +} + +// Item is a keyring item stored in a keyring backend. +// Local item +type Record_Local struct { + PrivKey *types.Any `protobuf:"bytes,1,opt,name=priv_key,json=privKey,proto3" json:"priv_key,omitempty"` + PrivKeyType string `protobuf:"bytes,2,opt,name=priv_key_type,json=privKeyType,proto3" json:"priv_key_type,omitempty"` +} + +func (m *Record_Local) Reset() { *m = Record_Local{} } +func (m *Record_Local) String() string { return proto.CompactTextString(m) } +func (*Record_Local) ProtoMessage() {} +func (*Record_Local) Descriptor() ([]byte, []int) { + return fileDescriptor_36d640103edea005, []int{0, 0} +} +func (m *Record_Local) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Record_Local) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Record_Local.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 *Record_Local) XXX_Merge(src proto.Message) { + xxx_messageInfo_Record_Local.Merge(m, src) +} +func (m *Record_Local) XXX_Size() int { + return m.Size() +} +func (m *Record_Local) XXX_DiscardUnknown() { + xxx_messageInfo_Record_Local.DiscardUnknown(m) +} + +var xxx_messageInfo_Record_Local proto.InternalMessageInfo + +// Ledger item +type Record_Ledger struct { + Path *hd.BIP44Params `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` +} + +func (m *Record_Ledger) Reset() { *m = Record_Ledger{} } +func (m *Record_Ledger) String() string { return proto.CompactTextString(m) } +func (*Record_Ledger) ProtoMessage() {} +func (*Record_Ledger) Descriptor() ([]byte, []int) { + return fileDescriptor_36d640103edea005, []int{0, 1} +} +func (m *Record_Ledger) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Record_Ledger) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Record_Ledger.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 *Record_Ledger) XXX_Merge(src proto.Message) { + xxx_messageInfo_Record_Ledger.Merge(m, src) +} +func (m *Record_Ledger) XXX_Size() int { + return m.Size() +} +func (m *Record_Ledger) XXX_DiscardUnknown() { + xxx_messageInfo_Record_Ledger.DiscardUnknown(m) +} + +var xxx_messageInfo_Record_Ledger proto.InternalMessageInfo + +// Multi item +type Record_Multi struct { +} + +func (m *Record_Multi) Reset() { *m = Record_Multi{} } +func (m *Record_Multi) String() string { return proto.CompactTextString(m) } +func (*Record_Multi) ProtoMessage() {} +func (*Record_Multi) Descriptor() ([]byte, []int) { + return fileDescriptor_36d640103edea005, []int{0, 2} +} +func (m *Record_Multi) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Record_Multi) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Record_Multi.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 *Record_Multi) XXX_Merge(src proto.Message) { + xxx_messageInfo_Record_Multi.Merge(m, src) +} +func (m *Record_Multi) XXX_Size() int { + return m.Size() +} +func (m *Record_Multi) XXX_DiscardUnknown() { + xxx_messageInfo_Record_Multi.DiscardUnknown(m) +} + +var xxx_messageInfo_Record_Multi proto.InternalMessageInfo + +// Offline item +type Record_Offline struct { +} + +func (m *Record_Offline) Reset() { *m = Record_Offline{} } +func (m *Record_Offline) String() string { return proto.CompactTextString(m) } +func (*Record_Offline) ProtoMessage() {} +func (*Record_Offline) Descriptor() ([]byte, []int) { + return fileDescriptor_36d640103edea005, []int{0, 3} +} +func (m *Record_Offline) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Record_Offline) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Record_Offline.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 *Record_Offline) XXX_Merge(src proto.Message) { + xxx_messageInfo_Record_Offline.Merge(m, src) +} +func (m *Record_Offline) XXX_Size() int { + return m.Size() +} +func (m *Record_Offline) XXX_DiscardUnknown() { + xxx_messageInfo_Record_Offline.DiscardUnknown(m) +} + +var xxx_messageInfo_Record_Offline proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Record)(nil), "cosmos.crypto.keyring.v1.Record") + proto.RegisterType((*Record_Local)(nil), "cosmos.crypto.keyring.v1.Record.Local") + proto.RegisterType((*Record_Ledger)(nil), "cosmos.crypto.keyring.v1.Record.Ledger") + proto.RegisterType((*Record_Multi)(nil), "cosmos.crypto.keyring.v1.Record.Multi") + proto.RegisterType((*Record_Offline)(nil), "cosmos.crypto.keyring.v1.Record.Offline") +} + +func init() { + proto.RegisterFile("cosmos/crypto/keyring/v1/record.proto", fileDescriptor_36d640103edea005) +} + +var fileDescriptor_36d640103edea005 = []byte{ + // 424 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4d, 0x8b, 0xd4, 0x30, + 0x18, 0xc7, 0x5b, 0xed, 0xb4, 0x4e, 0x16, 0x2f, 0x61, 0x0f, 0xb5, 0x48, 0x19, 0x16, 0xd4, 0x01, + 0xd9, 0x84, 0xd5, 0x39, 0x2f, 0xec, 0xe0, 0x61, 0x16, 0x15, 0x97, 0xe0, 0x49, 0x84, 0xa5, 0x2f, + 0x99, 0xb6, 0x4c, 0xdb, 0x84, 0x4c, 0x3b, 0x90, 0x2f, 0x21, 0x7e, 0xac, 0x3d, 0xee, 0xd1, 0xa3, + 0xce, 0x7c, 0x11, 0xc9, 0x93, 0xf6, 0xe0, 0x82, 0x8e, 0xa7, 0xa6, 0xe4, 0xf7, 0xfc, 0x5f, 0x1e, + 0x82, 0x5e, 0x64, 0x62, 0xdb, 0x88, 0x2d, 0xcd, 0x94, 0x96, 0x9d, 0xa0, 0x1b, 0xae, 0x55, 0xd5, + 0x16, 0x74, 0x77, 0x41, 0x15, 0xcf, 0x84, 0xca, 0x89, 0x54, 0xa2, 0x13, 0x38, 0xb4, 0x18, 0xb1, + 0x18, 0x19, 0x30, 0xb2, 0xbb, 0x88, 0x4e, 0x0b, 0x51, 0x08, 0x80, 0xa8, 0x39, 0x59, 0x3e, 0x7a, + 0x56, 0x08, 0x51, 0xd4, 0x9c, 0xc2, 0x5f, 0xda, 0xaf, 0x69, 0xd2, 0xea, 0xe1, 0xea, 0xf9, 0x9f, + 0x8e, 0x65, 0x6e, 0xcc, 0xca, 0xc1, 0xe8, 0xec, 0x9b, 0x87, 0x7c, 0x06, 0xce, 0x18, 0x23, 0xaf, + 0x4d, 0x1a, 0x1e, 0xba, 0x33, 0x77, 0x3e, 0x65, 0x70, 0xc6, 0xe7, 0x28, 0x90, 0x7d, 0x7a, 0xbb, + 0xe1, 0x3a, 0x7c, 0x34, 0x73, 0xe7, 0x27, 0x6f, 0x4e, 0x89, 0x75, 0x22, 0xa3, 0x13, 0xb9, 0x6a, + 0x35, 0xf3, 0x65, 0x9f, 0xbe, 0xe7, 0x1a, 0x5f, 0xa2, 0x49, 0x2d, 0xb2, 0xa4, 0x0e, 0x1f, 0x03, + 0xfc, 0x92, 0xfc, 0xad, 0x06, 0xb1, 0x9e, 0xe4, 0x83, 0xa1, 0x57, 0x0e, 0xb3, 0x63, 0xf8, 0x0a, + 0xf9, 0x35, 0xcf, 0x0b, 0xae, 0x42, 0x0f, 0x04, 0x5e, 0x1d, 0x17, 0x00, 0x7c, 0xe5, 0xb0, 0x61, + 0xd0, 0x44, 0x68, 0xfa, 0xba, 0xab, 0xc2, 0xc9, 0x7f, 0x46, 0xf8, 0x68, 0x68, 0x13, 0x01, 0xc6, + 0xf0, 0x3b, 0x14, 0x88, 0xf5, 0xba, 0xae, 0x5a, 0x1e, 0xfa, 0xa0, 0x30, 0x3f, 0xaa, 0xf0, 0xc9, + 0xf2, 0x2b, 0x87, 0x8d, 0xa3, 0xd1, 0x57, 0x34, 0x81, 0x6a, 0x98, 0xa2, 0x27, 0x52, 0x55, 0x3b, + 0xd8, 0xa0, 0xfb, 0x8f, 0x0d, 0x06, 0x86, 0x32, 0x2b, 0x3c, 0x43, 0x4f, 0xc7, 0x81, 0xdb, 0x4e, + 0x4b, 0x0e, 0x7b, 0x9f, 0xb2, 0x93, 0xe1, 0xfe, 0xb3, 0x96, 0x3c, 0xba, 0x44, 0xbe, 0xed, 0x8d, + 0x17, 0xc8, 0x93, 0x49, 0x57, 0x0e, 0xd2, 0xb3, 0x07, 0x51, 0xcb, 0xdc, 0xa4, 0x5c, 0x5e, 0xdf, + 0x2c, 0x16, 0x37, 0x89, 0x4a, 0x9a, 0x2d, 0x03, 0x3a, 0x0a, 0xd0, 0x04, 0x5a, 0x47, 0x53, 0x14, + 0x0c, 0xe1, 0x97, 0x3e, 0xf2, 0xaa, 0x8e, 0x37, 0xcb, 0xeb, 0xbb, 0x5f, 0xb1, 0x73, 0xb7, 0x8f, + 0xdd, 0xfb, 0x7d, 0xec, 0xfe, 0xdc, 0xc7, 0xee, 0xf7, 0x43, 0xec, 0xdc, 0x1f, 0x62, 0xe7, 0xc7, + 0x21, 0x76, 0xbe, 0xbc, 0x2e, 0xaa, 0xae, 0xec, 0x53, 0x92, 0x89, 0x86, 0x8e, 0xef, 0x0a, 0x3e, + 0xe7, 0xdb, 0x7c, 0xf3, 0xe0, 0x51, 0xa7, 0x3e, 0x34, 0x7c, 0xfb, 0x3b, 0x00, 0x00, 0xff, 0xff, + 0xe8, 0x29, 0x24, 0x50, 0xf4, 0x02, 0x00, 0x00, +} + +func (m *Record) 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 *Record) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Item != nil { + { + size := m.Item.Size() + i -= size + if _, err := m.Item.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + if m.PubKey != nil { + { + size, err := m.PubKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintRecord(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Record_Local_) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Local_) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Local != nil { + { + size, err := m.Local.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + return len(dAtA) - i, nil +} +func (m *Record_Ledger_) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Ledger_) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Ledger != nil { + { + size, err := m.Ledger.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + return len(dAtA) - i, nil +} +func (m *Record_Multi_) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Multi_) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Multi != nil { + { + size, err := m.Multi.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + return len(dAtA) - i, nil +} +func (m *Record_Offline_) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Offline_) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Offline != nil { + { + size, err := m.Offline.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + return len(dAtA) - i, nil +} +func (m *Record_Local) 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 *Record_Local) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Local) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PrivKeyType) > 0 { + i -= len(m.PrivKeyType) + copy(dAtA[i:], m.PrivKeyType) + i = encodeVarintRecord(dAtA, i, uint64(len(m.PrivKeyType))) + i-- + dAtA[i] = 0x12 + } + if m.PrivKey != nil { + { + size, err := m.PrivKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Record_Ledger) 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 *Record_Ledger) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Ledger) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Path != nil { + { + size, err := m.Path.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Record_Multi) 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 *Record_Multi) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Multi) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *Record_Offline) 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 *Record_Offline) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Record_Offline) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintRecord(dAtA []byte, offset int, v uint64) int { + offset -= sovRecord(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Record) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovRecord(uint64(l)) + } + if m.PubKey != nil { + l = m.PubKey.Size() + n += 1 + l + sovRecord(uint64(l)) + } + if m.Item != nil { + n += m.Item.Size() + } + return n +} + +func (m *Record_Local_) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Local != nil { + l = m.Local.Size() + n += 1 + l + sovRecord(uint64(l)) + } + return n +} +func (m *Record_Ledger_) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ledger != nil { + l = m.Ledger.Size() + n += 1 + l + sovRecord(uint64(l)) + } + return n +} +func (m *Record_Multi_) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Multi != nil { + l = m.Multi.Size() + n += 1 + l + sovRecord(uint64(l)) + } + return n +} +func (m *Record_Offline_) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Offline != nil { + l = m.Offline.Size() + n += 1 + l + sovRecord(uint64(l)) + } + return n +} +func (m *Record_Local) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PrivKey != nil { + l = m.PrivKey.Size() + n += 1 + l + sovRecord(uint64(l)) + } + l = len(m.PrivKeyType) + if l > 0 { + n += 1 + l + sovRecord(uint64(l)) + } + return n +} + +func (m *Record_Ledger) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Path != nil { + l = m.Path.Size() + n += 1 + l + sovRecord(uint64(l)) + } + return n +} + +func (m *Record_Multi) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *Record_Offline) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovRecord(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRecord(x uint64) (n int) { + return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Record) 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 ErrIntOverflowRecord + } + 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: Record: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Record: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PubKey == nil { + m.PubKey = &types.Any{} + } + if err := m.PubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Local", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Record_Local{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Item = &Record_Local_{v} + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ledger", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Record_Ledger{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Item = &Record_Ledger_{v} + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Multi", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Record_Multi{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Item = &Record_Multi_{v} + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Offline", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &Record_Offline{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Item = &Record_Offline_{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Record_Local) 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 ErrIntOverflowRecord + } + 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: Local: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Local: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PrivKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PrivKey == nil { + m.PrivKey = &types.Any{} + } + if err := m.PrivKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PrivKeyType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PrivKeyType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Record_Ledger) 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 ErrIntOverflowRecord + } + 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: Ledger: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Ledger: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRecord + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Path == nil { + m.Path = &hd.BIP44Params{} + } + if err := m.Path.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Record_Multi) 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 ErrIntOverflowRecord + } + 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: Multi: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Multi: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Record_Offline) 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 ErrIntOverflowRecord + } + 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: Offline: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Offline: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipRecord(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRecord + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRecord(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, ErrIntOverflowRecord + } + 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, ErrIntOverflowRecord + } + 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, ErrIntOverflowRecord + } + 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, ErrInvalidLengthRecord + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRecord + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthRecord + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRecord = fmt.Errorf("proto: unexpected end of group") +) diff --git a/crypto/keyring/record_test.go b/crypto/keyring/record_test.go new file mode 100644 index 000000000000..6c17379b4653 --- /dev/null +++ b/crypto/keyring/record_test.go @@ -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)) +} diff --git a/crypto/keyring/types.go b/crypto/keyring/types.go index 0b893ea4cccc..307eb9b3f097 100644 --- a/crypto/keyring/types.go +++ b/crypto/keyring/types.go @@ -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. diff --git a/crypto/keyring/types_test.go b/crypto/keyring/types_test.go index daf75b5d84f6..fa3e425d17c4 100644 --- a/crypto/keyring/types_test.go +++ b/crypto/keyring/types_test.go @@ -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()) + + restoredPubKey, err := restoredRecord.GetPubKey() + require.NoError(t, err) + require.Equal(t, pubKey, restoredPubKey) - restoredPath, err := restoredInfo.GetPath() + l = restoredRecord.GetLedger() + require.NotNil(t, l) + restoredPath := l.GetPath() require.NoError(t, err) require.Equal(t, path, restoredPath) } diff --git a/crypto/keys/multisig/multisig_test.go b/crypto/keys/multisig/multisig_test.go index e208f9db7338..433776a6e4f4 100644 --- a/crypto/keys/multisig/multisig_test.go +++ b/crypto/keys/multisig/multisig_test.go @@ -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)) diff --git a/crypto/ledger/ledger_mock.go b/crypto/ledger/ledger_mock.go index 4f7feb2c52de..93068474710d 100644 --- a/crypto/ledger/ledger_mock.go +++ b/crypto/ledger/ledger_mock.go @@ -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" diff --git a/crypto/ledger/ledger_test.go b/crypto/ledger/ledger_test.go index 61d50c7de801..fbc3b9e702ba 100644 --- a/crypto/ledger/ledger_test.go +++ b/crypto/ledger/ledger_test.go @@ -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) diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index af296094f071..36f3a8b116c6 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -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 + + + + + + + + + + + +

Top

+ +## cosmos/crypto/hd/v1/hd.proto + + + + + +### 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 | + + + + + + + + + + + + + + + + +

Top

+ +## cosmos/crypto/keyring/v1/record.proto + + + + + +### 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. | + + + + + + + + +### Record.Ledger +Ledger item + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `path` | [cosmos.crypto.hd.v1.BIP44Params](#cosmos.crypto.hd.v1.BIP44Params) | | | + + + + + + + + +### 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) | | | + + + + + + + + +### Record.Multi +Multi item + + + + + + + + +### Record.Offline +Offline item + + + + + diff --git a/go.sum b/go.sum index 380dd22c1907..0f0844f1891f 100644 --- a/go.sum +++ b/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= diff --git a/proto/cosmos/crypto/hd/v1/hd.proto b/proto/cosmos/crypto/hd/v1/hd.proto new file mode 100644 index 000000000000..eaf6ad40a9e7 --- /dev/null +++ b/proto/cosmos/crypto/hd/v1/hd.proto @@ -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; +} diff --git a/proto/cosmos/crypto/keyring/v1/record.proto b/proto/cosmos/crypto/keyring/v1/record.proto new file mode 100644 index 000000000000..757a8ab14084 --- /dev/null +++ b/proto/cosmos/crypto/keyring/v1/record.proto @@ -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 {} +} diff --git a/server/init.go b/server/init.go index 389b231e9975..e00ca1d35a70 100644 --- a/server/init.go +++ b/server/init.go @@ -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 } diff --git a/server/init_test.go b/server/init_test.go index d7439fe115f4..b52518056bf1 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -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) + addr1, err := k.GetAddress() require.NoError(t, err) - require.Equal(t, addr, info.GetAddress()) + 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) + addr1, err = k.GetAddress() require.NoError(t, err) - require.Equal(t, addr, info.GetAddress()) + 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" diff --git a/server/rosetta/lib/errors/errors_test.go b/server/rosetta/lib/errors/errors_test.go index 5502f09f7e3a..6efe446f5b2c 100644 --- a/server/rosetta/lib/errors/errors_test.go +++ b/server/rosetta/lib/errors/errors_test.go @@ -1,8 +1,9 @@ package errors import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestRegisterError(t *testing.T) { diff --git a/simapp/simd/cmd/genaccounts.go b/simapp/simd/cmd/genaccounts.go index 9e586943a2f3..1ed59f80518e 100644 --- a/simapp/simd/cmd/genaccounts.go +++ b/simapp/simd/cmd/genaccounts.go @@ -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]) diff --git a/simapp/simd/cmd/genaccounts_test.go b/simapp/simd/cmd/genaccounts_test.go index 0878fffe5008..ed6d93508567 100644 --- a/simapp/simd/cmd/genaccounts_test.go +++ b/simapp/simd/cmd/genaccounts_test.go @@ -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) diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index a5bdbced5956..8d467eedb907 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -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" diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index d5c60f0522ea..5d00e5920676 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -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 } diff --git a/simapp/simd/cmd/testnet_test.go b/simapp/simd/cmd/testnet_test.go index eafc3d4cdd5c..09134383a16c 100644 --- a/simapp/simd/cmd/testnet_test.go +++ b/simapp/simd/cmd/testnet_test.go @@ -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) { diff --git a/store/cachemulti/store_test.go b/store/cachemulti/store_test.go index 8747df9ef966..ef5bd5eaebb3 100644 --- a/store/cachemulti/store_test.go +++ b/store/cachemulti/store_test.go @@ -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) { diff --git a/telemetry/metrics.go b/telemetry/metrics.go index 53235e012bc8..686c7541ce12 100644 --- a/telemetry/metrics.go +++ b/telemetry/metrics.go @@ -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" diff --git a/telemetry/metrics_test.go b/telemetry/metrics_test.go index 39ffd85b9017..aa4c934bfb58 100644 --- a/telemetry/metrics_test.go +++ b/telemetry/metrics_test.go @@ -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" ) diff --git a/telemetry/wrapper.go b/telemetry/wrapper.go index 24722a7d63cc..e6542df86e19 100644 --- a/telemetry/wrapper.go +++ b/telemetry/wrapper.go @@ -3,7 +3,7 @@ package telemetry import ( "time" - metrics "github.com/armon/go-metrics" + "github.com/armon/go-metrics" ) // Common metric key constants diff --git a/testutil/network/network.go b/testutil/network/network.go index 738f0afd9682..8f3ace0c0c2f 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -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 } diff --git a/types/handler_test.go b/types/handler_test.go index 449d1b602f5c..c7fc961a5607 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -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) diff --git a/types/module/module_test.go b/types/module/module_test.go index 37fedd9d6296..49f6bf0ad03e 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -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" diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index ef5dcf101a1c..4f33ac75212c 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -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 + } + + addr, err := k.GetAddress() if err != nil { return err } - multisigPub := multisigInfo.GetPubKey().(*kmultisig.LegacyAminoPubKey) + 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 } diff --git a/x/auth/client/testutil/suite.go b/x/auth/client/testutil/suite.go index 5980e441f0b6..e461efd869a1 100644 --- a/x/auth/client/testutil/suite.go +++ b/x/auth/client/testutil/suite.go @@ -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") diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index fbba98d6870a..05a7c65567bc 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -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) } diff --git a/x/auth/tx/service_test.go b/x/auth/tx/service_test.go index 442087b7ea58..406cdf151b1f 100644 --- a/x/auth/tx/service_test.go +++ b/x/auth/tx/service_test.go @@ -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 diff --git a/x/authz/client/testutil/tx.go b/x/authz/client/testutil/tx.go index f1027fc8b12f..b379533cf71a 100644 --- a/x/authz/client/testutil/tx.go +++ b/x/authz/client/testutil/tx.go @@ -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) { diff --git a/x/feegrant/client/testutil/suite.go b/x/feegrant/client/testutil/suite.go index 0c716fec2c45..a4ebc216667a 100644 --- a/x/feegrant/client/testutil/suite.go +++ b/x/feegrant/client/testutil/suite.go @@ -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) + pub, err := k.GetPubKey() s.Require().NoError(err) - grantee := sdk.AccAddress(info.GetPubKey().Address()) + grantee := sdk.AccAddress(pub.Address()) clientCtx := val.ClientCtx diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index e8d736b2485d..c9128ae16dde 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -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: diff --git a/x/genutil/utils_test.go b/x/genutil/utils_test.go index df0984a4a150..1578f9968d74 100644 --- a/x/genutil/utils_test.go +++ b/x/genutil/utils_test.go @@ -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" ) diff --git a/x/gov/client/testutil/deposits.go b/x/gov/client/testutil/deposits.go index 43d6b8a44856..e13c005ba8a6 100644 --- a/x/gov/client/testutil/deposits.go +++ b/x/gov/client/testutil/deposits.go @@ -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 { diff --git a/x/staking/client/testutil/grpc.go b/x/staking/client/testutil/grpc.go index 97e5d5ec5478..78c39f857b59 100644 --- a/x/staking/client/testutil/grpc.go +++ b/x/staking/client/testutil/grpc.go @@ -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 diff --git a/x/staking/client/testutil/suite.go b/x/staking/client/testutil/suite.go index 21679d01d16d..e6c3bb5ad89c 100644 --- a/x/staking/client/testutil/suite.go +++ b/x/staking/client/testutil/suite.go @@ -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) + pub, err := k.GetPubKey() require.NoError(err) - newAddr := sdk.AccAddress(info.GetPubKey().Address()) + newAddr := sdk.AccAddress(pub.Address()) // Send some funds to the new account. _, err = banktestutil.MsgSendExec( diff --git a/x/staking/keeper/msg_server.go b/x/staking/keeper/msg_server.go index e32497a0dbf3..6b0fae7ac210 100644 --- a/x/staking/keeper/msg_server.go +++ b/x/staking/keeper/msg_server.go @@ -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" diff --git a/x/upgrade/client/testutil/cli_test.go b/x/upgrade/client/testutil/cli_test.go index f2cc15757b30..3c083e694726 100644 --- a/x/upgrade/client/testutil/cli_test.go +++ b/x/upgrade/client/testutil/cli_test.go @@ -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) { diff --git a/x/upgrade/client/testutil/suite.go b/x/upgrade/client/testutil/suite.go index 93ed107cc416..7611c8bb8fd5 100644 --- a/x/upgrade/client/testutil/suite.go +++ b/x/upgrade/client/testutil/suite.go @@ -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 {