-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
parse.go
151 lines (118 loc) · 3.38 KB
/
parse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package keys
import (
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/libs/cli"
yaml "gopkg.in/yaml.v2"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
)
func bech32Prefixes(config *sdk.Config) []string {
return []string{
config.GetBech32AccountAddrPrefix(),
config.GetBech32AccountPubPrefix(),
config.GetBech32ValidatorAddrPrefix(),
config.GetBech32ValidatorPubPrefix(),
config.GetBech32ConsensusAddrPrefix(),
config.GetBech32ConsensusPubPrefix(),
}
}
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(config *sdk.Config, bs []byte) bech32Output {
bech32Prefixes := bech32Prefixes(config)
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"))
}
// ParseKeyStringCommand parses an address from hex to bech32 and vice versa.
func ParseKeyStringCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "parse <hex-or-bech32-address>",
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,
}
return cmd
}
func parseKey(cmd *cobra.Command, args []string) error {
config, _ := sdk.GetSealedConfig(cmd.Context())
return doParseKey(cmd, config, args)
}
func doParseKey(cmd *cobra.Command, config *sdk.Config, args []string) error {
addr := strings.TrimSpace(args[0])
outstream := cmd.OutOrStdout()
if len(addr) == 0 {
return errors.New("couldn't parse empty input")
}
output, _ := cmd.Flags().GetString(cli.OutputFlag)
if !(runFromBech32(outstream, addr, output) || runFromHex(config, outstream, addr, output)) {
return errors.New("couldn't find valid bech32 nor hex data")
}
return nil
}
// print info from bech32
func runFromBech32(w io.Writer, bech32str, output string) bool {
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
if err != nil {
return false
}
displayParseKeyInfo(w, newHexOutput(hrp, bz), output)
return true
}
// print info from hex
func runFromHex(config *sdk.Config, w io.Writer, hexstr, output string) bool {
bz, err := hex.DecodeString(hexstr)
if err != nil {
return false
}
displayParseKeyInfo(w, newBech32Output(config, bz), output)
return true
}
func displayParseKeyInfo(w io.Writer, stringer fmt.Stringer, output string) {
var (
err error
out []byte
)
switch output {
case OutputFormatText:
out, err = yaml.Marshal(&stringer)
case OutputFormatJSON:
out, err = KeysCdc.MarshalJSON(stringer)
}
if err != nil {
panic(err)
}
_, _ = fmt.Fprintln(w, string(out))
}