From 4e70a37c6b9734deb47400ff5c5405aa1339c33c Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Thu, 2 May 2019 14:34:02 +0100 Subject: [PATCH] Merge PR #4228: gaiakeyutil -> gaiacli keys parse --- .../4228-merge-gaiakeyutil-into-gaiacli | 2 + Makefile | 2 - client/keys/parse.go | 133 ++++++++++++++++++ client/keys/parse_test.go | 28 ++++ client/keys/root.go | 1 + client/keys/root_test.go | 2 +- cmd/gaia/Makefile | 2 - cmd/gaia/cmd/gaiakeyutil/main.go | 60 -------- 8 files changed, 165 insertions(+), 65 deletions(-) create mode 100644 .pending/breaking/gaiacli/4228-merge-gaiakeyutil-into-gaiacli create mode 100644 client/keys/parse.go create mode 100644 client/keys/parse_test.go delete mode 100644 cmd/gaia/cmd/gaiakeyutil/main.go diff --git a/.pending/breaking/gaiacli/4228-merge-gaiakeyutil-into-gaiacli b/.pending/breaking/gaiacli/4228-merge-gaiakeyutil-into-gaiacli new file mode 100644 index 000000000..e986900a8 --- /dev/null +++ b/.pending/breaking/gaiacli/4228-merge-gaiakeyutil-into-gaiacli @@ -0,0 +1,2 @@ +#4228 Merge gaiakeyutil functionality into gaiacli keys. +Drop `gaiakeyutil` in favor of new `gaiacli keys parse` command. Syntax and semantic are preserved. diff --git a/Makefile b/Makefile index ff5f742e6..726fd2f3f 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,6 @@ else go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli go build -mod=readonly $(BUILD_FLAGS) -o build/gaiareplay ./cmd/gaia/cmd/gaiareplay - go build -mod=readonly $(BUILD_FLAGS) -o build/gaiakeyutil ./cmd/gaia/cmd/gaiakeyutil endif build-linux: go.sum @@ -94,7 +93,6 @@ install: go.sum check-ledger update_gaia_lite_docs go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiareplay - go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiakeyutil install_debug: go.sum go install -mod=readonly $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug diff --git a/client/keys/parse.go b/client/keys/parse.go new file mode 100644 index 000000000..b46736bbd --- /dev/null +++ b/client/keys/parse.go @@ -0,0 +1,133 @@ +package keys + +import ( + "encoding/hex" + "errors" + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/bech32" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var bech32Prefixes = []string{ + sdk.Bech32PrefixAccAddr, + sdk.Bech32PrefixAccPub, + sdk.Bech32PrefixValAddr, + sdk.Bech32PrefixValPub, + sdk.Bech32PrefixConsAddr, + sdk.Bech32PrefixConsPub, +} + +type hexOutput struct { + Human string `json:"human"` + Bytes string `json:"bytes"` +} + +func (ho hexOutput) String() string { + return fmt.Sprintf("Human readable part: %v\nBytes (hex): %s", ho.Human, ho.Bytes) +} + +func newHexOutput(human string, bs []byte) hexOutput { + return hexOutput{Human: human, Bytes: fmt.Sprintf("%X", bs)} +} + +type bech32Output struct { + Formats []string `json:"formats"` +} + +func newBech32Output(bs []byte) bech32Output { + out := bech32Output{Formats: make([]string, len(bech32Prefixes))} + for i, prefix := range bech32Prefixes { + bech32Addr, err := bech32.ConvertAndEncode(prefix, bs) + if err != nil { + panic(err) + } + out.Formats[i] = bech32Addr + } + + return out +} + +func (bo bech32Output) String() string { + out := make([]string, len(bo.Formats)) + + for i, format := range bo.Formats { + out[i] = fmt.Sprintf(" - %s", format) + } + + return fmt.Sprintf("Bech32 Formats:\n%s", strings.Join(out, "\n")) +} + +func parseKeyStringCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "parse ", + Short: "Parse address from hex to bech32 and vice versa", + Long: `Convert and print to stdout key addresses and fingerprints from +hexadecimal into bech32 cosmos prefixed format and vice versa. +`, + Args: cobra.ExactArgs(1), + RunE: parseKey, + } + cmd.Flags().Bool(client.FlagIndentResponse, false, "Indent JSON output") + + return cmd +} + +func parseKey(_ *cobra.Command, args []string) error { + addr := strings.TrimSpace(args[0]) + if len(addr) == 0 { + return errors.New("couldn't parse empty input") + } + if !(runFromBech32(addr) || runFromHex(addr)) { + return errors.New("couldn't find valid bech32 nor hex data") + } + return nil +} + +// print info from bech32 +func runFromBech32(bech32str string) bool { + hrp, bz, err := bech32.DecodeAndConvert(bech32str) + if err != nil { + return false + } + displayParseKeyInfo(newHexOutput(hrp, bz)) + return true +} + +// print info from hex +func runFromHex(hexstr string) bool { + bz, err := hex.DecodeString(hexstr) + if err != nil { + return false + } + displayParseKeyInfo(newBech32Output(bz)) + return true +} + +func displayParseKeyInfo(stringer fmt.Stringer) { + switch viper.Get(cli.OutputFlag) { + case OutputFormatText: + fmt.Printf("%s\n", stringer) + + case OutputFormatJSON: + var out []byte + var err error + + if viper.GetBool(client.FlagIndentResponse) { + out, err = cdc.MarshalJSONIndent(stringer, "", " ") + if err != nil { + panic(err) + } + } else { + out = cdc.MustMarshalJSON(stringer) + } + + fmt.Println(string(out)) + } +} diff --git a/client/keys/parse_test.go b/client/keys/parse_test.go new file mode 100644 index 000000000..33e6c6ab0 --- /dev/null +++ b/client/keys/parse_test.go @@ -0,0 +1,28 @@ +package keys + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseKey(t *testing.T) { + bech32str := "cosmos104ytdpvrx9284zd50v9ep8c6j7pua7dkk0x3ek" + hexstr := "EB5AE9872103497EC092EF901027049E4F39200C60040D3562CD7F104A39F62E6E5A39A818F4" + + tests := []struct { + name string + args []string + wantErr bool + }{ + {"empty input", []string{""}, true}, + {"invalid input", []string{"invalid"}, true}, + {"bech32", []string{bech32str}, false}, + {"hex", []string{hexstr}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.wantErr, parseKey(nil, tt.args) != nil) + }) + } +} diff --git a/client/keys/root.go b/client/keys/root.go index e49b57d4a..32dc146f2 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -26,6 +26,7 @@ func Commands() *cobra.Command { client.LineBreak, deleteKeyCommand(), updateKeyCommand(), + parseKeyStringCommand(), ) return cmd } diff --git a/client/keys/root_test.go b/client/keys/root_test.go index 1cc2db425..07c1460ac 100644 --- a/client/keys/root_test.go +++ b/client/keys/root_test.go @@ -11,5 +11,5 @@ func TestCommands(t *testing.T) { assert.NotNil(t, rootCommands) // Commands are registered - assert.Equal(t, 7, len(rootCommands.Commands())) + assert.Equal(t, 8, len(rootCommands.Commands())) } diff --git a/cmd/gaia/Makefile b/cmd/gaia/Makefile index f966ee436..66710ffc6 100644 --- a/cmd/gaia/Makefile +++ b/cmd/gaia/Makefile @@ -72,7 +72,6 @@ else go build -mod=readonly $(BUILD_FLAGS) -o build/gaiad ../../cmd/gaia/cmd/gaiad go build -mod=readonly $(BUILD_FLAGS) -o build/gaiacli ../../cmd/gaia/cmd/gaiacli go build -mod=readonly $(BUILD_FLAGS) -o build/gaiareplay ../../cmd/gaia/cmd/gaiareplay - go build -mod=readonly $(BUILD_FLAGS) -o build/gaiakeyutil ../../cmd/gaia/cmd/gaiakeyutil endif build-linux: ../../go.sum @@ -82,7 +81,6 @@ install: ../../go.sum check-ledger go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiad go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiacli go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiareplay - go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiakeyutil install-debug: ../../go.sum go install -mod=readonly $(BUILD_FLAGS) ../../cmd/gaia/cmd/gaiadebug diff --git a/cmd/gaia/cmd/gaiakeyutil/main.go b/cmd/gaia/cmd/gaiakeyutil/main.go deleted file mode 100644 index 30aebed3b..000000000 --- a/cmd/gaia/cmd/gaiakeyutil/main.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "encoding/hex" - "fmt" - "os" - - "github.com/tendermint/tendermint/libs/bech32" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var bech32Prefixes = []string{ - sdk.Bech32PrefixAccAddr, - sdk.Bech32PrefixAccPub, - sdk.Bech32PrefixValAddr, - sdk.Bech32PrefixValPub, - sdk.Bech32PrefixConsAddr, - sdk.Bech32PrefixConsPub, -} - -func main() { - if len(os.Args) < 2 { - fmt.Println("Must specify an input string") - } - arg := os.Args[1] - runFromBech32(arg) - runFromHex(arg) -} - -// Print info from bech32. -func runFromBech32(bech32str string) { - hrp, bz, err := bech32.DecodeAndConvert(bech32str) - if err != nil { - fmt.Println("Not a valid bech32 string") - return - } - fmt.Println("Bech32 parse:") - fmt.Printf("Human readible part: %v\nBytes (hex): %X\n", - hrp, - bz, - ) -} - -func runFromHex(hexaddr string) { - bz, err := hex.DecodeString(hexaddr) - if err != nil { - fmt.Println("Not a valid hex string") - return - } - fmt.Println("Hex parse:") - fmt.Println("Bech32 formats:") - for _, prefix := range bech32Prefixes { - bech32Addr, err := bech32.ConvertAndEncode(prefix, bz) - if err != nil { - panic(err) - } - fmt.Println(" - " + bech32Addr) - } -}