github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/auth/client/cli/tx_multisign.go (about) 1 package cli 2 3 import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "strings" 9 10 "github.com/spf13/cobra" 11 "github.com/spf13/viper" 12 13 "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/multisig" 14 15 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 16 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags" 17 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys" 19 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 20 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/version" 21 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils" 22 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types" 23 ) 24 25 // GetSignCommand returns the sign command 26 func GetMultiSignCommand(cdc *codec.Codec) *cobra.Command { 27 cmd := &cobra.Command{ 28 Use: "multisign [file] [name] [[signature]...]", 29 Short: "Generate multisig signatures for transactions generated offline", 30 Long: strings.TrimSpace( 31 fmt.Sprintf(`Sign transactions created with the --generate-only flag that require multisig signatures. 32 33 Read signature(s) from [signature] file(s), generate a multisig signature compliant to the 34 multisig key [name], and attach it to the transaction read from [file]. 35 36 Example: 37 $ %s multisign transaction.json k1k2k3 k1sig.json k2sig.json k3sig.json 38 39 If the flag --signature-only flag is on, it outputs a JSON representation 40 of the generated signature only. 41 42 The --offline flag makes sure that the client will not reach out to an external node. 43 Thus account number or sequence number lookups will not be performed and it is 44 recommended to set such parameters manually. 45 `, 46 version.ClientName, 47 ), 48 ), 49 RunE: makeMultiSignCmd(cdc), 50 Args: cobra.MinimumNArgs(3), 51 } 52 53 cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") 54 cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query a full node") 55 cmd.Flags().String(flagOutfile, "", "The document will be written to the given file instead of STDOUT") 56 57 // Add the flags here and return the command 58 return flags.PostCommands(cmd)[0] 59 } 60 61 func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { 62 return func(cmd *cobra.Command, args []string) (err error) { 63 stdTx, err := utils.ReadStdTxFromFile(cdc, args[0]) 64 if err != nil { 65 return 66 } 67 68 inBuf := bufio.NewReader(cmd.InOrStdin()) 69 kb, err := keys.NewKeyring(sdk.KeyringServiceName(), 70 viper.GetString(flags.FlagKeyringBackend), viper.GetString(flags.FlagHome), inBuf) 71 if err != nil { 72 return 73 } 74 75 multisigInfo, err := kb.Get(args[1]) 76 if err != nil { 77 return 78 } 79 if multisigInfo.GetType() != keys.TypeMulti { 80 return fmt.Errorf("%q must be of type %s: %s", args[1], keys.TypeMulti, multisigInfo.GetType()) 81 } 82 83 multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) 84 multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys)) 85 cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) 86 txBldr := types.NewTxBuilderFromCLI(inBuf) 87 88 if !viper.GetBool(flagOffline) { 89 accnum, seq, err := types.NewAccountRetriever(cliCtx).GetAccountNumberSequence(multisigInfo.GetAddress()) 90 if err != nil { 91 return err 92 } 93 94 txBldr = txBldr.WithAccountNumber(accnum).WithSequence(seq) 95 } 96 97 // read each signature and add it to the multisig if valid 98 for i := 2; i < len(args); i++ { 99 stdSig, err := readAndUnmarshalStdSignature(cdc, args[i]) 100 if err != nil { 101 return err 102 } 103 104 // Validate each signature 105 sigBytes := types.StdSignBytes( 106 txBldr.ChainID(), txBldr.AccountNumber(), txBldr.Sequence(), 107 stdTx.Fee, stdTx.GetMsgs(), stdTx.GetMemo(), 108 ) 109 if ok := stdSig.PubKey.VerifyBytes(sigBytes, stdSig.Signature); !ok { 110 return fmt.Errorf("couldn't verify signature") 111 } 112 if err := multisigSig.AddSignatureFromPubKey(stdSig.Signature, stdSig.PubKey, multisigPub.PubKeys); err != nil { 113 return err 114 } 115 } 116 117 newStdSig := types.StdSignature{Signature: cdc.MustMarshalBinaryBare(multisigSig), PubKey: multisigPub} 118 newTx := types.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, []types.StdSignature{newStdSig}, stdTx.GetMemo()) 119 120 sigOnly := viper.GetBool(flagSigOnly) 121 var json []byte 122 switch { 123 case sigOnly && cliCtx.Indent: 124 json, err = cdc.MarshalJSONIndent(newTx.Signatures[0], "", " ") 125 case sigOnly && !cliCtx.Indent: 126 json, err = cdc.MarshalJSON(newTx.Signatures[0]) 127 case !sigOnly && cliCtx.Indent: 128 json, err = cdc.MarshalJSONIndent(newTx, "", " ") 129 default: 130 json, err = cdc.MarshalJSON(newTx) 131 } 132 if err != nil { 133 return err 134 } 135 136 if viper.GetString(flagOutfile) == "" { 137 fmt.Printf("%s\n", json) 138 return 139 } 140 141 fp, err := os.OpenFile( 142 viper.GetString(flagOutfile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644, 143 ) 144 if err != nil { 145 return err 146 } 147 defer fp.Close() 148 149 fmt.Fprintf(fp, "%s\n", json) 150 151 return 152 } 153 } 154 155 func readAndUnmarshalStdSignature(cdc *codec.Codec, filename string) (stdSig types.StdSignature, err error) { 156 var bytes []byte 157 if bytes, err = ioutil.ReadFile(filename); err != nil { 158 return 159 } 160 if err = cdc.UnmarshalJSON(bytes, &stdSig); err != nil { 161 return 162 } 163 return 164 }