github.com/cosmos/cosmos-sdk@v0.50.10/client/debug/main.go (about) 1 package debug 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "fmt" 7 "strconv" 8 "strings" 9 10 "github.com/spf13/cobra" 11 12 errorsmod "cosmossdk.io/errors" 13 14 "github.com/cosmos/cosmos-sdk/client" 15 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" 16 "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" 17 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 18 sdk "github.com/cosmos/cosmos-sdk/types" 19 legacybech32 "github.com/cosmos/cosmos-sdk/types/bech32/legacybech32" //nolint:staticcheck // we do old keys, they're keys after all. 20 "github.com/cosmos/cosmos-sdk/types/errors" 21 "github.com/cosmos/cosmos-sdk/version" 22 ) 23 24 var ( 25 flagPubkeyType = "type" 26 ed = "ed25519" 27 ) 28 29 // Cmd creates a main CLI command 30 func Cmd() *cobra.Command { 31 cmd := &cobra.Command{ 32 Use: "debug", 33 Short: "Tool for helping with debugging your application", 34 RunE: client.ValidateCmd, 35 } 36 37 cmd.AddCommand(CodecCmd()) 38 cmd.AddCommand(PubkeyCmd()) 39 cmd.AddCommand(PubkeyRawCmd()) 40 cmd.AddCommand(AddrCmd()) 41 cmd.AddCommand(RawBytesCmd()) 42 cmd.AddCommand(PrefixesCmd()) 43 44 return cmd 45 } 46 47 // CodecCmd creates and returns a new codec debug cmd. 48 func CodecCmd() *cobra.Command { 49 cmd := &cobra.Command{ 50 Use: "codec", 51 Short: "Tool for helping with debugging your application codec", 52 RunE: client.ValidateCmd, 53 } 54 55 cmd.AddCommand(getCodecInterfaces()) 56 cmd.AddCommand(getCodecInterfaceImpls()) 57 58 return cmd 59 } 60 61 // getCodecInterfaces creates and returns a new cmd used for listing all registered interfaces on the application codec. 62 func getCodecInterfaces() *cobra.Command { 63 return &cobra.Command{ 64 Use: "list-interfaces", 65 Short: "List all registered interface type URLs", 66 Long: "List all registered interface type URLs using the application codec", 67 RunE: func(cmd *cobra.Command, args []string) error { 68 clientCtx := client.GetClientContextFromCmd(cmd) 69 iFaces := clientCtx.Codec.InterfaceRegistry().ListAllInterfaces() 70 for _, iFace := range iFaces { 71 cmd.Println(iFace) 72 } 73 return nil 74 }, 75 } 76 } 77 78 // getCodecInterfaceImpls creates and returns a new cmd used for listing all registered implemenations of a given interface on the application codec. 79 func getCodecInterfaceImpls() *cobra.Command { 80 return &cobra.Command{ 81 Use: "list-implementations [interface]", 82 Short: "List the registered type URLs for the provided interface", 83 Long: "List the registered type URLs that can be used for the provided interface name using the application codec", 84 Args: cobra.ExactArgs(1), 85 RunE: func(cmd *cobra.Command, args []string) error { 86 clientCtx := client.GetClientContextFromCmd(cmd) 87 impls := clientCtx.Codec.InterfaceRegistry().ListImplementations(args[0]) 88 for _, imp := range impls { 89 cmd.Println(imp) 90 } 91 return nil 92 }, 93 } 94 } 95 96 // getPubKeyFromString decodes SDK PubKey using JSON marshaler. 97 func getPubKeyFromString(ctx client.Context, pkstr string) (cryptotypes.PubKey, error) { 98 var pk cryptotypes.PubKey 99 err := ctx.Codec.UnmarshalInterfaceJSON([]byte(pkstr), &pk) 100 return pk, err 101 } 102 103 func PubkeyCmd() *cobra.Command { 104 return &cobra.Command{ 105 Use: "pubkey [pubkey]", 106 Short: "Decode a pubkey from proto JSON", 107 Long: fmt.Sprintf(`Decode a pubkey from proto JSON and display it's address. 108 109 Example: 110 $ %s debug pubkey '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AurroA7jvfPd1AadmmOvWM2rJSwipXfRf8yD6pLbA2DJ"}' 111 `, version.AppName), 112 Args: cobra.ExactArgs(1), 113 RunE: func(cmd *cobra.Command, args []string) error { 114 clientCtx := client.GetClientContextFromCmd(cmd) 115 pk, err := getPubKeyFromString(clientCtx, args[0]) 116 if err != nil { 117 return err 118 } 119 cmd.Println("Address:", pk.Address()) 120 cmd.Println("PubKey Hex:", hex.EncodeToString(pk.Bytes())) 121 return nil 122 }, 123 } 124 } 125 126 func bytesToPubkey(bz []byte, keytype string) (cryptotypes.PubKey, bool) { 127 if keytype == ed { 128 if len(bz) == ed25519.PubKeySize { 129 return &ed25519.PubKey{Key: bz}, true 130 } 131 } 132 133 if len(bz) == secp256k1.PubKeySize { 134 return &secp256k1.PubKey{Key: bz}, true 135 } 136 return nil, false 137 } 138 139 // getPubKeyFromRawString returns a PubKey (PubKeyEd25519 or PubKeySecp256k1) by attempting 140 // to decode the pubkey string from hex, base64, and finally bech32. If all 141 // encodings fail, an error is returned. 142 func getPubKeyFromRawString(pkstr, keytype string) (cryptotypes.PubKey, error) { 143 // Try hex decoding 144 bz, err := hex.DecodeString(pkstr) 145 if err == nil { 146 pk, ok := bytesToPubkey(bz, keytype) 147 if ok { 148 return pk, nil 149 } 150 } 151 152 bz, err = base64.StdEncoding.DecodeString(pkstr) 153 if err == nil { 154 pk, ok := bytesToPubkey(bz, keytype) 155 if ok { 156 return pk, nil 157 } 158 } 159 160 pk, err := legacybech32.UnmarshalPubKey(legacybech32.AccPK, pkstr) //nolint:staticcheck // we do old keys, they're keys after all. 161 if err == nil { 162 return pk, nil 163 } 164 165 pk, err = legacybech32.UnmarshalPubKey(legacybech32.ValPK, pkstr) //nolint:staticcheck // we do old keys, they're keys after all. 166 if err == nil { 167 return pk, nil 168 } 169 170 pk, err = legacybech32.UnmarshalPubKey(legacybech32.ConsPK, pkstr) //nolint:staticcheck // we do old keys, they're keys after all. 171 if err == nil { 172 return pk, nil 173 } 174 175 return nil, fmt.Errorf("pubkey '%s' invalid; expected hex, base64, or bech32 of correct size", pkstr) 176 } 177 178 func PubkeyRawCmd() *cobra.Command { 179 cmd := &cobra.Command{ 180 Use: "pubkey-raw [pubkey] -t [{ed25519, secp256k1}]", 181 Short: "Decode a ED25519 or secp256k1 pubkey from hex, base64, or bech32", 182 Long: "Decode a pubkey from hex, base64, or bech32.", 183 Example: fmt.Sprintf(` 184 %s debug pubkey-raw 8FCA9D6D1F80947FD5E9A05309259746F5F72541121766D5F921339DD061174A 185 %s debug pubkey-raw j8qdbR+AlH/V6aBTCSWXRvX3JUESF2bV+SEzndBhF0o= 186 %s debug pubkey-raw cosmospub1zcjduepq3l9f6mglsz28l40f5pfsjfvhgm6lwf2pzgtkd40eyyeem5rpza9q47axrz 187 `, version.AppName, version.AppName, version.AppName), 188 Args: cobra.ExactArgs(1), 189 RunE: func(cmd *cobra.Command, args []string) error { 190 clientCtx := client.GetClientContextFromCmd(cmd) 191 192 pubkeyType, err := cmd.Flags().GetString(flagPubkeyType) 193 if err != nil { 194 return err 195 } 196 pubkeyType = strings.ToLower(pubkeyType) 197 if pubkeyType != "secp256k1" && pubkeyType != ed { 198 return errorsmod.Wrapf(errors.ErrInvalidType, "invalid pubkey type, expected oneof ed25519 or secp256k1") 199 } 200 201 pk, err := getPubKeyFromRawString(args[0], pubkeyType) 202 if err != nil { 203 return err 204 } 205 206 var consensusPub string 207 edPK, ok := pk.(*ed25519.PubKey) 208 if ok && pubkeyType == ed { 209 consensusPub, err = legacybech32.MarshalPubKey(legacybech32.ConsPK, edPK) //nolint:staticcheck // we do old keys, they're keys after all. 210 if err != nil { 211 return err 212 } 213 214 cmd.Printf("Hex: %X\n", edPK.Key) 215 } 216 cmd.Println("Parsed key as", pk.Type()) 217 218 pubKeyJSONBytes, err := clientCtx.LegacyAmino.MarshalJSON(pk) 219 if err != nil { 220 return err 221 } 222 accPub, err := legacybech32.MarshalPubKey(legacybech32.AccPK, pk) //nolint:staticcheck // we do old keys, they're keys after all. 223 if err != nil { 224 return err 225 } 226 valPub, err := legacybech32.MarshalPubKey(legacybech32.ValPK, pk) //nolint:staticcheck // we do old keys, they're keys after all. 227 if err != nil { 228 return err 229 } 230 cmd.Println("Address:", pk.Address()) 231 cmd.Println("JSON (base64):", string(pubKeyJSONBytes)) 232 cmd.Println("Bech32 Acc:", accPub) 233 cmd.Println("Bech32 Validator Operator:", valPub) 234 if pubkeyType == "ed25519" { 235 cmd.Println("Bech32 Validator Consensus:", consensusPub) 236 } 237 238 return nil 239 }, 240 } 241 cmd.Flags().StringP(flagPubkeyType, "t", ed, "Pubkey type to decode (oneof secp256k1, ed25519)") 242 return cmd 243 } 244 245 func AddrCmd() *cobra.Command { 246 return &cobra.Command{ 247 Use: "addr [address]", 248 Short: "Convert an address between hex and bech32", 249 Long: fmt.Sprintf(`Convert an address between hex encoding and bech32. 250 251 Example: 252 $ %s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg 253 `, version.AppName), 254 Args: cobra.ExactArgs(1), 255 RunE: func(cmd *cobra.Command, args []string) error { 256 addrString := args[0] 257 // try hex, then bech32 258 var ( 259 addr []byte 260 err error 261 ) 262 decodeFns := []func(text string) ([]byte, error){ 263 hex.DecodeString, 264 func(text string) ([]byte, error) { return sdk.AccAddressFromBech32(text) }, 265 func(text string) ([]byte, error) { return sdk.ValAddressFromBech32(text) }, 266 func(text string) ([]byte, error) { return sdk.ConsAddressFromBech32(text) }, 267 } 268 errs := make([]any, 0, len(decodeFns)) 269 for _, fn := range decodeFns { 270 if addr, err = fn(addrString); err == nil { 271 break 272 } 273 errs = append(errs, err) 274 } 275 if len(errs) == len(decodeFns) { 276 errTags := []string{ 277 "hex", "bech32 acc", "bech32 val", "bech32 con", 278 } 279 format := "" 280 for i := range errs { 281 if format != "" { 282 format += ", " 283 } 284 format += errTags[i] + ": %w" 285 } 286 return fmt.Errorf("expected hex or bech32. Got errors: "+format, errs...) 287 } 288 289 cmd.Println("Address:", addr) 290 cmd.Printf("Address (hex): %X\n", addr) 291 cmd.Printf("Bech32 Acc: %s\n", sdk.AccAddress(addr)) 292 cmd.Printf("Bech32 Val: %s\n", sdk.ValAddress(addr)) 293 cmd.Printf("Bech32 Con: %s\n", sdk.ConsAddress(addr)) 294 return nil 295 }, 296 } 297 } 298 299 func RawBytesCmd() *cobra.Command { 300 return &cobra.Command{ 301 Use: "raw-bytes <raw-bytes>", 302 Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex", 303 Long: "Convert raw-bytes to hex.", 304 Example: fmt.Sprintf("%s debug raw-bytes '[72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 110 100]'", version.AppName), 305 Args: cobra.ExactArgs(1), 306 RunE: func(_ *cobra.Command, args []string) error { 307 stringBytes := args[0] 308 stringBytes = strings.Trim(stringBytes, "[") 309 stringBytes = strings.Trim(stringBytes, "]") 310 spl := strings.Split(stringBytes, " ") 311 312 byteArray := []byte{} 313 for _, s := range spl { 314 b, err := strconv.ParseInt(s, 10, 8) 315 if err != nil { 316 return err 317 } 318 byteArray = append(byteArray, byte(b)) 319 } 320 fmt.Printf("%X\n", byteArray) 321 return nil 322 }, 323 } 324 } 325 326 func PrefixesCmd() *cobra.Command { 327 return &cobra.Command{ 328 Use: "prefixes", 329 Short: "List prefixes used for Human-Readable Part (HRP) in Bech32", 330 Long: "List prefixes used in Bech32 addresses.", 331 Example: fmt.Sprintf("$ %s debug prefixes", version.AppName), 332 RunE: func(cmd *cobra.Command, args []string) error { 333 cmd.Printf("Bech32 Acc: %s\n", sdk.GetConfig().GetBech32AccountAddrPrefix()) 334 cmd.Printf("Bech32 Val: %s\n", sdk.GetConfig().GetBech32ValidatorAddrPrefix()) 335 cmd.Printf("Bech32 Con: %s\n", sdk.GetConfig().GetBech32ConsensusAddrPrefix()) 336 return nil 337 }, 338 } 339 }