github.com/cosmos/cosmos-sdk@v0.50.10/client/keys/show.go (about) 1 package keys 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/spf13/cobra" 8 9 errorsmod "cosmossdk.io/errors" 10 11 "github.com/cosmos/cosmos-sdk/client" 12 "github.com/cosmos/cosmos-sdk/client/flags" 13 "github.com/cosmos/cosmos-sdk/crypto/keyring" 14 "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" 15 "github.com/cosmos/cosmos-sdk/crypto/ledger" 16 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 17 sdk "github.com/cosmos/cosmos-sdk/types" 18 sdkerr "github.com/cosmos/cosmos-sdk/types/errors" 19 ) 20 21 const ( 22 // FlagAddress is the flag for the user's address on the command line. 23 FlagAddress = "address" 24 // FlagPublicKey represents the user's public key on the command line. 25 FlagPublicKey = "pubkey" 26 // FlagBechPrefix defines a desired Bech32 prefix encoding for a key. 27 FlagBechPrefix = "bech" 28 // FlagDevice indicates that the information should be shown in the device 29 FlagDevice = "device" 30 31 flagMultiSigThreshold = "multisig-threshold" 32 ) 33 34 // ShowKeysCmd shows key information for a given key name. 35 func ShowKeysCmd() *cobra.Command { 36 cmd := &cobra.Command{ 37 Use: "show [name_or_address [name_or_address...]]", 38 Short: "Retrieve key information by name or address", 39 Long: `Display keys details. If multiple names or addresses are provided, 40 then an ephemeral multisig key will be created under the name "multi" 41 consisting of all the keys provided by name and multisig threshold.`, 42 Args: cobra.MinimumNArgs(1), 43 RunE: runShowCmd, 44 } 45 f := cmd.Flags() 46 f.String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)") 47 f.BoolP(FlagAddress, "a", false, "Output the address only (cannot be used with --output)") 48 f.BoolP(FlagPublicKey, "p", false, "Output the public key only (cannot be used with --output)") 49 f.BoolP(FlagDevice, "d", false, "Output the address in a ledger device (cannot be used with --pubkey)") 50 f.Int(flagMultiSigThreshold, 1, "K out of N required signatures") 51 52 return cmd 53 } 54 55 func runShowCmd(cmd *cobra.Command, args []string) (err error) { 56 k := new(keyring.Record) 57 clientCtx, err := client.GetClientQueryContext(cmd) 58 if err != nil { 59 return err 60 } 61 outputFormat := clientCtx.OutputFormat 62 63 if len(args) == 1 { 64 k, err = fetchKey(clientCtx.Keyring, args[0]) 65 if err != nil { 66 return fmt.Errorf("%s is not a valid name or address: %v", args[0], err) 67 } 68 } else { 69 pks := make([]cryptotypes.PubKey, len(args)) 70 for i, keyref := range args { 71 k, err := fetchKey(clientCtx.Keyring, keyref) 72 if err != nil { 73 return fmt.Errorf("%s is not a valid name or address: %v", keyref, err) 74 } 75 key, err := k.GetPubKey() 76 if err != nil { 77 return err 78 } 79 pks[i] = key 80 } 81 82 multisigThreshold, _ := cmd.Flags().GetInt(flagMultiSigThreshold) 83 84 if err := validateMultisigThreshold(multisigThreshold, len(args)); err != nil { 85 return err 86 } 87 88 multikey := multisig.NewLegacyAminoPubKey(multisigThreshold, pks) 89 k, err = keyring.NewMultiRecord(k.Name, multikey) 90 if err != nil { 91 return err 92 } 93 } 94 95 isShowAddr, _ := cmd.Flags().GetBool(FlagAddress) 96 isShowPubKey, _ := cmd.Flags().GetBool(FlagPublicKey) 97 isShowDevice, _ := cmd.Flags().GetBool(FlagDevice) 98 99 isOutputSet := false 100 tmp := cmd.Flag(flags.FlagOutput) 101 if tmp != nil { 102 isOutputSet = tmp.Changed 103 } 104 105 if isShowAddr && isShowPubKey { 106 return errors.New("cannot use both --address and --pubkey at once") 107 } 108 109 if isOutputSet && (isShowAddr || isShowPubKey) { 110 return errors.New("cannot use --output with --address or --pubkey") 111 } 112 113 bechPrefix, _ := cmd.Flags().GetString(FlagBechPrefix) 114 bechKeyOut, err := getBechKeyOut(bechPrefix) 115 if err != nil { 116 return err 117 } 118 119 if isOutputSet { 120 clientCtx.OutputFormat, _ = cmd.Flags().GetString(flags.FlagOutput) 121 } 122 123 switch { 124 case isShowAddr, isShowPubKey: 125 ko, err := bechKeyOut(k) 126 if err != nil { 127 return err 128 } 129 out := ko.Address 130 if isShowPubKey { 131 out = ko.PubKey 132 } 133 134 if _, err := fmt.Fprintln(cmd.OutOrStdout(), out); err != nil { 135 return err 136 } 137 default: 138 if err := printKeyringRecord(cmd.OutOrStdout(), k, bechKeyOut, outputFormat); err != nil { 139 return err 140 } 141 } 142 143 if isShowDevice { 144 if isShowPubKey { 145 return fmt.Errorf("the device flag (-d) can only be used for addresses not pubkeys") 146 } 147 if bechPrefix != "acc" { 148 return fmt.Errorf("the device flag (-d) can only be used for accounts") 149 } 150 151 // Override and show in the device 152 if k.GetType() != keyring.TypeLedger { 153 return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices") 154 } 155 156 ledgerItem := k.GetLedger() 157 if ledgerItem == nil { 158 return errors.New("unable to get ledger item") 159 } 160 161 pk, err := k.GetPubKey() 162 if err != nil { 163 return err 164 } 165 166 return ledger.ShowAddress(*ledgerItem.Path, pk, sdk.GetConfig().GetBech32AccountAddrPrefix()) 167 } 168 169 return nil 170 } 171 172 func fetchKey(kb keyring.Keyring, keyref string) (*keyring.Record, error) { 173 // firstly check if the keyref is a key name of a key registered in a keyring. 174 k, err := kb.Key(keyref) 175 // if the key is not there or if we have a problem with a keyring itself then we move to a 176 // fallback: searching for key by address. 177 178 if err == nil || !errorsmod.IsOf(err, sdkerr.ErrIO, sdkerr.ErrKeyNotFound) { 179 return k, err 180 } 181 182 accAddr, err := sdk.AccAddressFromBech32(keyref) 183 if err != nil { 184 return k, err 185 } 186 187 k, err = kb.KeyByAddress(accAddr) 188 return k, errorsmod.Wrap(err, "Invalid key") 189 } 190 191 func validateMultisigThreshold(k, nKeys int) error { 192 if k <= 0 { 193 return fmt.Errorf("threshold must be a positive integer") 194 } 195 if nKeys < k { 196 return fmt.Errorf( 197 "threshold k of n multisignature: %d < %d", nKeys, k) 198 } 199 return nil 200 } 201 202 func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) { 203 switch bechPrefix { 204 case sdk.PrefixAccount: 205 return MkAccKeyOutput, nil 206 case sdk.PrefixValidator: 207 return MkValKeyOutput, nil 208 case sdk.PrefixConsensus: 209 return MkConsKeyOutput, nil 210 } 211 212 return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix) 213 }