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  }