Skip to content

Commit 305c0ab

Browse files
JulianToledanomergify[bot]
authored andcommitted
feat: import hex keys (#17424)
(cherry picked from commit 0e05785) # Conflicts: # CHANGELOG.md # crypto/keyring/keyring.go # crypto/keyring/keyring_test.go
1 parent 72a6397 commit 305c0ab

File tree

7 files changed

+729
-2
lines changed

7 files changed

+729
-2
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
3737

3838
## [Unreleased]
3939

40+
<<<<<<< HEAD
41+
=======
42+
### Features
43+
44+
* (keyring) [#17424](https://github.com/cosmos/cosmos-sdk/pull/17424) Allows to import private keys encoded in hex.
45+
* (x/bank) [#16795](https://github.com/cosmos/cosmos-sdk/pull/16852) Add `DenomMetadataByQueryString` query in bank module to support metadata query by query string.
46+
* (baseapp) [#16239](https://github.com/cosmos/cosmos-sdk/pull/16239) Add Gas Limits to allow node operators to resource bound queries.
47+
* (baseapp) [#17393](https://github.com/cosmos/cosmos-sdk/pull/17394) Check BlockID Flag on Votes in `ValidateVoteExtensions`
48+
49+
>>>>>>> 0e057851c (feat: import hex keys (#17424))
4050
### Improvements
4151

4252
* (x/gov) [#17387](https://github.com/cosmos/cosmos-sdk/pull/17387) Add `MsgSubmitProposal` `SetMsgs` method.

client/keys/import.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package keys
22

33
import (
44
"bufio"
5+
"fmt"
56
"os"
67

78
"github.com/spf13/cobra"
89

910
"github.com/cosmos/cosmos-sdk/client"
11+
"github.com/cosmos/cosmos-sdk/client/flags"
1012
"github.com/cosmos/cosmos-sdk/client/input"
13+
"github.com/cosmos/cosmos-sdk/crypto/hd"
14+
"github.com/cosmos/cosmos-sdk/version"
1115
)
1216

1317
// ImportKeyCommand imports private keys from a keyfile.
@@ -38,3 +42,22 @@ func ImportKeyCommand() *cobra.Command {
3842
},
3943
}
4044
}
45+
46+
func ImportKeyHexCommand() *cobra.Command {
47+
cmd := &cobra.Command{
48+
Use: "import-hex <name> <hex>",
49+
Short: "Import private keys into the local keybase",
50+
Long: fmt.Sprintf("Import hex encoded private key into the local keybase.\nSupported key-types can be obtained with:\n%s list-key-types", version.AppName),
51+
Args: cobra.ExactArgs(2),
52+
RunE: func(cmd *cobra.Command, args []string) error {
53+
clientCtx, err := client.GetClientQueryContext(cmd)
54+
if err != nil {
55+
return err
56+
}
57+
keyType, _ := cmd.Flags().GetString(flags.FlagKeyType)
58+
return clientCtx.Keyring.ImportPrivKeyHex(args[0], args[1], keyType)
59+
},
60+
}
61+
cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "private key signing algorithm kind")
62+
return cmd
63+
}

client/keys/import_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,60 @@ HbP+c6JmeJy9JXe2rbbF1QtCX1gLqGcDQPBXiCtFvP7/8wTZtVOPj8vREzhZ9ElO
115115
})
116116
}
117117
}
118+
119+
func Test_runImportHexCmd(t *testing.T) {
120+
cdc := moduletestutil.MakeTestEncodingConfig().Codec
121+
testCases := []struct {
122+
name string
123+
keyringBackend string
124+
hexKey string
125+
keyType string
126+
expectError bool
127+
}{
128+
{
129+
name: "test backend success",
130+
keyringBackend: keyring.BackendTest,
131+
hexKey: "0xa3e57952e835ed30eea86a2993ac2a61c03e74f2085b3635bd94aa4d7ae0cfdf",
132+
keyType: "secp256k1",
133+
},
134+
}
135+
136+
for _, tc := range testCases {
137+
t.Run(tc.name, func(t *testing.T) {
138+
cmd := ImportKeyHexCommand()
139+
cmd.Flags().AddFlagSet(Commands().PersistentFlags())
140+
mockIn := testutil.ApplyMockIODiscardOutErr(cmd)
141+
142+
// Now add a temporary keybase
143+
kbHome := t.TempDir()
144+
kb, err := keyring.New(sdk.KeyringServiceName(), tc.keyringBackend, kbHome, nil, cdc)
145+
require.NoError(t, err)
146+
147+
clientCtx := client.Context{}.
148+
WithKeyringDir(kbHome).
149+
WithKeyring(kb).
150+
WithInput(mockIn).
151+
WithCodec(cdc)
152+
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
153+
154+
t.Cleanup(cleanupKeys(t, kb, "keyname1"))
155+
156+
defer func() {
157+
_ = os.RemoveAll(kbHome)
158+
}()
159+
160+
cmd.SetArgs([]string{
161+
"keyname1", tc.hexKey,
162+
fmt.Sprintf("--%s=%s", flags.FlagKeyType, tc.keyType),
163+
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, tc.keyringBackend),
164+
})
165+
166+
err = cmd.ExecuteContext(ctx)
167+
if tc.expectError {
168+
require.Error(t, err)
169+
} else {
170+
require.NoError(t, err)
171+
}
172+
})
173+
}
174+
}

client/keys/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ The pass backend requires GnuPG: https://gnupg.org/
4242
AddKeyCommand(),
4343
ExportKeyCommand(),
4444
ImportKeyCommand(),
45+
ImportKeyHexCommand(),
4546
ListKeysCmd(),
4647
ListKeyTypesCmd(),
4748
ShowKeysCmd(),

client/keys/root_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ func TestCommands(t *testing.T) {
1111
assert.Assert(t, rootCommands != nil)
1212

1313
// Commands are registered
14-
assert.Equal(t, 11, len(rootCommands.Commands()))
14+
assert.Equal(t, 12, len(rootCommands.Commands()))
1515
}

crypto/keyring/keyring.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const (
4343

4444
// temporary pass phrase for exporting a key during a key rename
4545
passPhrase = "temp"
46+
// prefix for exported hex private keys
47+
hexPrefix = "0x"
4648
)
4749

4850
var (
@@ -113,7 +115,8 @@ type Signer interface {
113115
type Importer interface {
114116
// ImportPrivKey imports ASCII armored passphrase-encrypted private keys.
115117
ImportPrivKey(uid, armor, passphrase string) error
116-
118+
// ImportPrivKeyHex imports hex encoded keys.
119+
ImportPrivKeyHex(uid, privKey, algoStr string) error
117120
// ImportPubKey imports ASCII armored public keys.
118121
ImportPubKey(uid string, armor string) error
119122
}
@@ -333,7 +336,34 @@ func (ks keystore) ImportPrivKey(uid, armor, passphrase string) error {
333336
return nil
334337
}
335338

339+
<<<<<<< HEAD
336340
func (ks keystore) ImportPubKey(uid string, armor string) error {
341+
=======
342+
func (ks keystore) ImportPrivKeyHex(uid, privKey, algoStr string) error {
343+
if _, err := ks.Key(uid); err == nil {
344+
return errorsmod.Wrap(ErrOverwriteKey, uid)
345+
}
346+
if privKey[:2] == hexPrefix {
347+
privKey = privKey[2:]
348+
}
349+
decodedPriv, err := hex.DecodeString(privKey)
350+
if err != nil {
351+
return err
352+
}
353+
algo, err := NewSigningAlgoFromString(algoStr, ks.options.SupportedAlgos)
354+
if err != nil {
355+
return err
356+
}
357+
priv := algo.Generate()(decodedPriv)
358+
_, err = ks.writeLocalKey(uid, priv)
359+
if err != nil {
360+
return err
361+
}
362+
return nil
363+
}
364+
365+
func (ks keystore) ImportPubKey(uid, armor string) error {
366+
>>>>>>> 0e057851c (feat: import hex keys (#17424))
337367
if _, err := ks.Key(uid); err == nil {
338368
return fmt.Errorf("cannot overwrite key: %s", uid)
339369
}

0 commit comments

Comments
 (0)