github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/client/keys/show.go (about)

     1  package keys
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/spf13/cobra"
     8  	"github.com/spf13/viper"
     9  
    10  	tmcrypto "github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    11  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/multisig"
    12  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/cli"
    13  
    14  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
    15  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto"
    16  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys"
    17  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    18  )
    19  
    20  const (
    21  	// FlagAddress is the flag for the user's address on the command line.
    22  	FlagAddress = "address"
    23  	// FlagPublicKey represents the user's public key on the command line.
    24  	FlagPublicKey = "pubkey"
    25  	// FlagBechPrefix defines a desired Bech32 prefix encoding for a key.
    26  	FlagBechPrefix = "bech"
    27  	// FlagDevice indicates that the information should be shown in the device
    28  	FlagDevice = "device"
    29  
    30  	flagMultiSigThreshold = "multisig-threshold"
    31  
    32  	defaultMultiSigKeyName = "multi"
    33  )
    34  
    35  // ShowKeysCmd shows key information for a given key name.
    36  func ShowKeysCmd() *cobra.Command {
    37  	cmd := &cobra.Command{
    38  		Use:   "show [name [name...]]",
    39  		Short: "Show key info for the given name",
    40  		Long: `Return public details of a single local key. If multiple names are
    41  provided, then an ephemeral multisig key will be created under the name "multi"
    42  consisting of all the keys provided by name and multisig threshold.`,
    43  		Args: cobra.MinimumNArgs(1),
    44  		RunE: runShowCmd,
    45  	}
    46  
    47  	cmd.Flags().String(FlagBechPrefix, sdk.PrefixAccount, "The Bech32 prefix encoding for a key (acc|val|cons)")
    48  	cmd.Flags().BoolP(FlagAddress, "a", false, "Output the address only (overrides --output)")
    49  	cmd.Flags().BoolP(FlagPublicKey, "p", false, "Output the public key only (overrides --output)")
    50  	cmd.Flags().BoolP(FlagDevice, "d", false, "Output the address in a ledger device")
    51  	cmd.Flags().Uint(flagMultiSigThreshold, 1, "K out of N required signatures")
    52  	cmd.Flags().Bool(flags.FlagIndentResponse, false, "Add indent to JSON response")
    53  
    54  	return cmd
    55  }
    56  
    57  func runShowCmd(cmd *cobra.Command, args []string) (err error) {
    58  	var info keys.Info
    59  
    60  	kb, err := keys.NewKeyring(sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), cmd.InOrStdin())
    61  	if err != nil {
    62  		return err
    63  	}
    64  	if len(args) == 1 {
    65  		info, err = kb.Get(args[0])
    66  		if err != nil {
    67  			return err
    68  		}
    69  	} else {
    70  		pks := make([]tmcrypto.PubKey, len(args))
    71  		for i, keyName := range args {
    72  			info, err := kb.Get(keyName)
    73  			if err != nil {
    74  				return err
    75  			}
    76  
    77  			pks[i] = info.GetPubKey()
    78  		}
    79  
    80  		multisigThreshold := viper.GetInt(flagMultiSigThreshold)
    81  		err = validateMultisigThreshold(multisigThreshold, len(args))
    82  		if err != nil {
    83  			return err
    84  		}
    85  
    86  		multikey := multisig.NewPubKeyMultisigThreshold(multisigThreshold, pks)
    87  		info = keys.NewMultiInfo(defaultMultiSigKeyName, multikey)
    88  	}
    89  
    90  	isShowAddr := viper.GetBool(FlagAddress)
    91  	isShowPubKey := viper.GetBool(FlagPublicKey)
    92  	isShowDevice := viper.GetBool(FlagDevice)
    93  
    94  	isOutputSet := false
    95  	tmp := cmd.Flag(cli.OutputFlag)
    96  	if tmp != nil {
    97  		isOutputSet = tmp.Changed
    98  	}
    99  
   100  	if isShowAddr && isShowPubKey {
   101  		return errors.New("cannot use both --address and --pubkey at once")
   102  	}
   103  
   104  	if isOutputSet && (isShowAddr || isShowPubKey) {
   105  		return errors.New("cannot use --output with --address or --pubkey")
   106  	}
   107  
   108  	bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	switch {
   114  	case isShowAddr:
   115  		printKeyAddress(info, bechKeyOut)
   116  	case isShowPubKey:
   117  		printPubKey(info, bechKeyOut)
   118  	default:
   119  		printKeyInfo(info, bechKeyOut)
   120  	}
   121  
   122  	if isShowDevice {
   123  		if isShowPubKey {
   124  			return fmt.Errorf("the device flag (-d) can only be used for addresses not pubkeys")
   125  		}
   126  		if viper.GetString(FlagBechPrefix) != "acc" {
   127  			return fmt.Errorf("the device flag (-d) can only be used for accounts")
   128  		}
   129  		// Override and show in the device
   130  		if info.GetType() != keys.TypeLedger {
   131  			return fmt.Errorf("the device flag (-d) can only be used for accounts stored in devices")
   132  		}
   133  
   134  		hdpath, err := info.GetPath()
   135  		if err != nil {
   136  			return nil
   137  		}
   138  
   139  		return crypto.LedgerShowAddress(*hdpath, info.GetPubKey())
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func validateMultisigThreshold(k, nKeys int) error {
   146  	if k <= 0 {
   147  		return fmt.Errorf("threshold must be a positive integer")
   148  	}
   149  	if nKeys < k {
   150  		return fmt.Errorf(
   151  			"threshold k of n multisignature: %d < %d", nKeys, k)
   152  	}
   153  	return nil
   154  }
   155  
   156  func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
   157  	switch bechPrefix {
   158  	case sdk.PrefixAccount:
   159  		return keys.Bech32KeyOutput, nil
   160  	case sdk.PrefixValidator:
   161  		return keys.Bech32ValKeyOutput, nil
   162  	case sdk.PrefixConsensus:
   163  		return keys.Bech32ConsKeyOutput, nil
   164  	}
   165  
   166  	return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
   167  }