github.com/cosmos/cosmos-sdk@v0.50.10/client/tx/tx.go (about) 1 package tx 2 3 import ( 4 "bufio" 5 "context" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "os" 10 11 gogogrpc "github.com/cosmos/gogoproto/grpc" 12 "github.com/spf13/pflag" 13 14 "github.com/cosmos/cosmos-sdk/client" 15 "github.com/cosmos/cosmos-sdk/client/input" 16 cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" 17 sdk "github.com/cosmos/cosmos-sdk/types" 18 sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 19 "github.com/cosmos/cosmos-sdk/types/tx" 20 "github.com/cosmos/cosmos-sdk/types/tx/signing" 21 authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 22 ) 23 24 // GenerateOrBroadcastTxCLI will either generate and print an unsigned transaction 25 // or sign it and broadcast it returning an error upon failure. 26 func GenerateOrBroadcastTxCLI(clientCtx client.Context, flagSet *pflag.FlagSet, msgs ...sdk.Msg) error { 27 txf, err := NewFactoryCLI(clientCtx, flagSet) 28 if err != nil { 29 return err 30 } 31 32 return GenerateOrBroadcastTxWithFactory(clientCtx, txf, msgs...) 33 } 34 35 // GenerateOrBroadcastTxWithFactory will either generate and print an unsigned transaction 36 // or sign it and broadcast it returning an error upon failure. 37 func GenerateOrBroadcastTxWithFactory(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { 38 // Validate all msgs before generating or broadcasting the tx. 39 // We were calling ValidateBasic separately in each CLI handler before. 40 // Right now, we're factorizing that call inside this function. 41 // ref: https://github.com/cosmos/cosmos-sdk/pull/9236#discussion_r623803504 42 for _, msg := range msgs { 43 m, ok := msg.(sdk.HasValidateBasic) 44 if !ok { 45 continue 46 } 47 48 if err := m.ValidateBasic(); err != nil { 49 return err 50 } 51 } 52 53 // If the --aux flag is set, we simply generate and print the AuxSignerData. 54 if clientCtx.IsAux { 55 auxSignerData, err := makeAuxSignerData(clientCtx, txf, msgs...) 56 if err != nil { 57 return err 58 } 59 60 return clientCtx.PrintProto(&auxSignerData) 61 } 62 63 if clientCtx.GenerateOnly { 64 return txf.PrintUnsignedTx(clientCtx, msgs...) 65 } 66 67 return BroadcastTx(clientCtx, txf, msgs...) 68 } 69 70 // BroadcastTx attempts to generate, sign and broadcast a transaction with the 71 // given set of messages. It will also simulate gas requirements if necessary. 72 // It will return an error upon failure. 73 func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { 74 txf, err := txf.Prepare(clientCtx) 75 if err != nil { 76 return err 77 } 78 79 if txf.SimulateAndExecute() || clientCtx.Simulate { 80 if clientCtx.Offline { 81 return errors.New("cannot estimate gas in offline mode") 82 } 83 84 _, adjusted, err := CalculateGas(clientCtx, txf, msgs...) 85 if err != nil { 86 return err 87 } 88 89 txf = txf.WithGas(adjusted) 90 _, _ = fmt.Fprintf(os.Stderr, "%s\n", GasEstimateResponse{GasEstimate: txf.Gas()}) 91 } 92 93 if clientCtx.Simulate { 94 return nil 95 } 96 97 tx, err := txf.BuildUnsignedTx(msgs...) 98 if err != nil { 99 return err 100 } 101 102 if !clientCtx.SkipConfirm { 103 encoder := txf.txConfig.TxJSONEncoder() 104 if encoder == nil { 105 return errors.New("failed to encode transaction: tx json encoder is nil") 106 } 107 108 txBytes, err := encoder(tx.GetTx()) 109 if err != nil { 110 return fmt.Errorf("failed to encode transaction: %w", err) 111 } 112 113 if err := clientCtx.PrintRaw(json.RawMessage(txBytes)); err != nil { 114 _, _ = fmt.Fprintf(os.Stderr, "error: %v\n%s\n", err, txBytes) 115 } 116 117 buf := bufio.NewReader(os.Stdin) 118 ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr) 119 if err != nil { 120 _, _ = fmt.Fprintf(os.Stderr, "error: %v\ncanceled transaction\n", err) 121 return err 122 } 123 if !ok { 124 _, _ = fmt.Fprintln(os.Stderr, "canceled transaction") 125 return nil 126 } 127 } 128 129 if err = Sign(clientCtx.CmdContext, txf, clientCtx.FromName, tx, true); err != nil { 130 return err 131 } 132 133 txBytes, err := clientCtx.TxConfig.TxEncoder()(tx.GetTx()) 134 if err != nil { 135 return err 136 } 137 138 // broadcast to a CometBFT node 139 res, err := clientCtx.BroadcastTx(txBytes) 140 if err != nil { 141 return err 142 } 143 144 return clientCtx.PrintProto(res) 145 } 146 147 // CalculateGas simulates the execution of a transaction and returns the 148 // simulation response obtained by the query and the adjusted gas amount. 149 func CalculateGas( 150 clientCtx gogogrpc.ClientConn, txf Factory, msgs ...sdk.Msg, 151 ) (*tx.SimulateResponse, uint64, error) { 152 txBytes, err := txf.BuildSimTx(msgs...) 153 if err != nil { 154 return nil, 0, err 155 } 156 157 txSvcClient := tx.NewServiceClient(clientCtx) 158 simRes, err := txSvcClient.Simulate(context.Background(), &tx.SimulateRequest{ 159 TxBytes: txBytes, 160 }) 161 if err != nil { 162 return nil, 0, err 163 } 164 165 return simRes, uint64(txf.GasAdjustment() * float64(simRes.GasInfo.GasUsed)), nil 166 } 167 168 // SignWithPrivKey signs a given tx with the given private key, and returns the 169 // corresponding SignatureV2 if the signing is successful. 170 func SignWithPrivKey( 171 ctx context.Context, 172 signMode signing.SignMode, signerData authsigning.SignerData, 173 txBuilder client.TxBuilder, priv cryptotypes.PrivKey, txConfig client.TxConfig, 174 accSeq uint64, 175 ) (signing.SignatureV2, error) { 176 var sigV2 signing.SignatureV2 177 178 // Generate the bytes to be signed. 179 signBytes, err := authsigning.GetSignBytesAdapter( 180 ctx, txConfig.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) 181 if err != nil { 182 return sigV2, err 183 } 184 185 // Sign those bytes 186 signature, err := priv.Sign(signBytes) 187 if err != nil { 188 return sigV2, err 189 } 190 191 // Construct the SignatureV2 struct 192 sigData := signing.SingleSignatureData{ 193 SignMode: signMode, 194 Signature: signature, 195 } 196 197 sigV2 = signing.SignatureV2{ 198 PubKey: priv.PubKey(), 199 Data: &sigData, 200 Sequence: accSeq, 201 } 202 203 return sigV2, nil 204 } 205 206 // countDirectSigners counts the number of DIRECT signers in a signature data. 207 func countDirectSigners(data signing.SignatureData) int { 208 switch data := data.(type) { 209 case *signing.SingleSignatureData: 210 if data.SignMode == signing.SignMode_SIGN_MODE_DIRECT { 211 return 1 212 } 213 214 return 0 215 case *signing.MultiSignatureData: 216 directSigners := 0 217 for _, d := range data.Signatures { 218 directSigners += countDirectSigners(d) 219 } 220 221 return directSigners 222 default: 223 panic("unreachable case") 224 } 225 } 226 227 // checkMultipleSigners checks that there can be maximum one DIRECT signer in 228 // a tx. 229 func checkMultipleSigners(tx authsigning.Tx) error { 230 directSigners := 0 231 sigsV2, err := tx.GetSignaturesV2() 232 if err != nil { 233 return err 234 } 235 for _, sig := range sigsV2 { 236 directSigners += countDirectSigners(sig.Data) 237 if directSigners > 1 { 238 return sdkerrors.ErrNotSupported.Wrap("txs signed with CLI can have maximum 1 DIRECT signer") 239 } 240 } 241 242 return nil 243 } 244 245 // Sign signs a given tx with a named key. The bytes signed over are canconical. 246 // The resulting signature will be added to the transaction builder overwriting the previous 247 // ones if overwrite=true (otherwise, the signature will be appended). 248 // Signing a transaction with mutltiple signers in the DIRECT mode is not supprted and will 249 // return an error. 250 // An error is returned upon failure. 251 func Sign(ctx context.Context, txf Factory, name string, txBuilder client.TxBuilder, overwriteSig bool) error { 252 if txf.keybase == nil { 253 return errors.New("keybase must be set prior to signing a transaction") 254 } 255 256 var err error 257 signMode := txf.signMode 258 if signMode == signing.SignMode_SIGN_MODE_UNSPECIFIED { 259 // use the SignModeHandler's default mode if unspecified 260 signMode, err = authsigning.APISignModeToInternal(txf.txConfig.SignModeHandler().DefaultMode()) 261 if err != nil { 262 return err 263 } 264 } 265 266 k, err := txf.keybase.Key(name) 267 if err != nil { 268 return err 269 } 270 271 pubKey, err := k.GetPubKey() 272 if err != nil { 273 return err 274 } 275 276 signerData := authsigning.SignerData{ 277 ChainID: txf.chainID, 278 AccountNumber: txf.accountNumber, 279 Sequence: txf.sequence, 280 PubKey: pubKey, 281 Address: sdk.AccAddress(pubKey.Address()).String(), 282 } 283 284 // For SIGN_MODE_DIRECT, calling SetSignatures calls setSignerInfos on 285 // TxBuilder under the hood, and SignerInfos is needed to generated the 286 // sign bytes. This is the reason for setting SetSignatures here, with a 287 // nil signature. 288 // 289 // Note: this line is not needed for SIGN_MODE_LEGACY_AMINO, but putting it 290 // also doesn't affect its generated sign bytes, so for code's simplicity 291 // sake, we put it here. 292 sigData := signing.SingleSignatureData{ 293 SignMode: signMode, 294 Signature: nil, 295 } 296 sig := signing.SignatureV2{ 297 PubKey: pubKey, 298 Data: &sigData, 299 Sequence: txf.Sequence(), 300 } 301 302 var prevSignatures []signing.SignatureV2 303 if !overwriteSig { 304 prevSignatures, err = txBuilder.GetTx().GetSignaturesV2() 305 if err != nil { 306 return err 307 } 308 } 309 // Overwrite or append signer infos. 310 var sigs []signing.SignatureV2 311 if overwriteSig { 312 sigs = []signing.SignatureV2{sig} 313 } else { 314 sigs = append(sigs, prevSignatures...) 315 sigs = append(sigs, sig) 316 } 317 if err := txBuilder.SetSignatures(sigs...); err != nil { 318 return err 319 } 320 321 if err := checkMultipleSigners(txBuilder.GetTx()); err != nil { 322 return err 323 } 324 325 bytesToSign, err := authsigning.GetSignBytesAdapter(ctx, txf.txConfig.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) 326 if err != nil { 327 return err 328 } 329 330 // Sign those bytes 331 sigBytes, _, err := txf.keybase.Sign(name, bytesToSign, signMode) 332 if err != nil { 333 return err 334 } 335 336 // Construct the SignatureV2 struct 337 sigData = signing.SingleSignatureData{ 338 SignMode: signMode, 339 Signature: sigBytes, 340 } 341 sig = signing.SignatureV2{ 342 PubKey: pubKey, 343 Data: &sigData, 344 Sequence: txf.Sequence(), 345 } 346 347 if overwriteSig { 348 err = txBuilder.SetSignatures(sig) 349 } else { 350 prevSignatures = append(prevSignatures, sig) 351 err = txBuilder.SetSignatures(prevSignatures...) 352 } 353 354 if err != nil { 355 return fmt.Errorf("unable to set signatures on payload: %w", err) 356 } 357 358 // Run optional preprocessing if specified. By default, this is unset 359 // and will return nil. 360 return txf.PreprocessTx(name, txBuilder) 361 } 362 363 // GasEstimateResponse defines a response definition for tx gas estimation. 364 type GasEstimateResponse struct { 365 GasEstimate uint64 `json:"gas_estimate" yaml:"gas_estimate"` 366 } 367 368 func (gr GasEstimateResponse) String() string { 369 return fmt.Sprintf("gas estimate: %d", gr.GasEstimate) 370 } 371 372 // makeAuxSignerData generates an AuxSignerData from the client inputs. 373 func makeAuxSignerData(clientCtx client.Context, f Factory, msgs ...sdk.Msg) (tx.AuxSignerData, error) { 374 b := NewAuxTxBuilder() 375 fromAddress, name, _, err := client.GetFromFields(clientCtx, clientCtx.Keyring, clientCtx.From) 376 if err != nil { 377 return tx.AuxSignerData{}, err 378 } 379 380 b.SetAddress(fromAddress.String()) 381 if clientCtx.Offline { 382 b.SetAccountNumber(f.accountNumber) 383 b.SetSequence(f.sequence) 384 } else { 385 accNum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, fromAddress) 386 if err != nil { 387 return tx.AuxSignerData{}, err 388 } 389 b.SetAccountNumber(accNum) 390 b.SetSequence(seq) 391 } 392 393 err = b.SetMsgs(msgs...) 394 if err != nil { 395 return tx.AuxSignerData{}, err 396 } 397 398 err = b.SetSignMode(f.SignMode()) 399 if err != nil { 400 return tx.AuxSignerData{}, err 401 } 402 403 key, err := clientCtx.Keyring.Key(name) 404 if err != nil { 405 return tx.AuxSignerData{}, err 406 } 407 408 pub, err := key.GetPubKey() 409 if err != nil { 410 return tx.AuxSignerData{}, err 411 } 412 413 err = b.SetPubKey(pub) 414 if err != nil { 415 return tx.AuxSignerData{}, err 416 } 417 418 b.SetChainID(clientCtx.ChainID) 419 signBz, err := b.GetSignBytes() 420 if err != nil { 421 return tx.AuxSignerData{}, err 422 } 423 424 sig, _, err := clientCtx.Keyring.Sign(name, signBz, f.signMode) 425 if err != nil { 426 return tx.AuxSignerData{}, err 427 } 428 b.SetSignature(sig) 429 430 return b.GetAuxSignerData() 431 }