github.com/Finschia/finschia-sdk@v0.49.1/client/tx/tx.go (about)

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