github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/builder.go (about)

     1  package tx
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/cosmos/gogoproto/proto"
     8  	protov2 "google.golang.org/protobuf/proto"
     9  
    10  	errorsmod "cosmossdk.io/errors"
    11  
    12  	"github.com/cosmos/cosmos-sdk/client"
    13  	"github.com/cosmos/cosmos-sdk/codec"
    14  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    15  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    16  	sdk "github.com/cosmos/cosmos-sdk/types"
    17  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    18  	"github.com/cosmos/cosmos-sdk/types/tx"
    19  	"github.com/cosmos/cosmos-sdk/types/tx/signing"
    20  	"github.com/cosmos/cosmos-sdk/x/auth/ante"
    21  	authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
    22  )
    23  
    24  // wrapper is a wrapper around the tx.Tx proto.Message which retain the raw
    25  // body and auth_info bytes.
    26  type wrapper struct {
    27  	cdc codec.Codec
    28  
    29  	tx *tx.Tx
    30  
    31  	// bodyBz represents the protobuf encoding of TxBody. This should be encoding
    32  	// from the client using TxRaw if the tx was decoded from the wire
    33  	bodyBz []byte
    34  
    35  	// authInfoBz represents the protobuf encoding of TxBody. This should be encoding
    36  	// from the client using TxRaw if the tx was decoded from the wire
    37  	authInfoBz []byte
    38  
    39  	txBodyHasUnknownNonCriticals bool
    40  
    41  	signers [][]byte
    42  	msgsV2  []protov2.Message
    43  }
    44  
    45  var (
    46  	_ authsigning.Tx             = &wrapper{}
    47  	_ client.TxBuilder           = &wrapper{}
    48  	_ ante.HasExtensionOptionsTx = &wrapper{}
    49  	_ ExtensionOptionsTxBuilder  = &wrapper{}
    50  )
    51  
    52  // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions.
    53  type ExtensionOptionsTxBuilder interface {
    54  	client.TxBuilder
    55  
    56  	SetExtensionOptions(...*codectypes.Any)
    57  	SetNonCriticalExtensionOptions(...*codectypes.Any)
    58  }
    59  
    60  func newBuilder(cdc codec.Codec) *wrapper {
    61  	w := &wrapper{
    62  		cdc: cdc,
    63  		tx: &tx.Tx{
    64  			Body: &tx.TxBody{},
    65  			AuthInfo: &tx.AuthInfo{
    66  				Fee: &tx.Fee{},
    67  			},
    68  		},
    69  	}
    70  	return w
    71  }
    72  
    73  func (w *wrapper) GetMsgs() []sdk.Msg {
    74  	return w.tx.GetMsgs()
    75  }
    76  
    77  func (w *wrapper) GetMsgsV2() ([]protov2.Message, error) {
    78  	if w.msgsV2 == nil {
    79  		err := w.initSignersAndMsgsV2()
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  	}
    84  
    85  	return w.msgsV2, nil
    86  }
    87  
    88  func (w *wrapper) ValidateBasic() error {
    89  	if w.tx == nil {
    90  		return fmt.Errorf("bad Tx")
    91  	}
    92  
    93  	if err := w.tx.ValidateBasic(); err != nil {
    94  		return err
    95  	}
    96  
    97  	sigs := w.tx.Signatures
    98  	signers, err := w.GetSigners()
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	if len(sigs) != len(signers) {
   104  		return errorsmod.Wrapf(
   105  			sdkerrors.ErrUnauthorized,
   106  			"wrong number of signers; expected %d, got %d", len(signers), len(sigs),
   107  		)
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func (w *wrapper) getBodyBytes() []byte {
   114  	if len(w.bodyBz) == 0 {
   115  		// if bodyBz is empty, then marshal the body. bodyBz will generally
   116  		// be set to nil whenever SetBody is called so the result of calling
   117  		// this method should always return the correct bytes. Note that after
   118  		// decoding bodyBz is derived from TxRaw so that it matches what was
   119  		// transmitted over the wire
   120  		var err error
   121  		w.bodyBz, err = proto.Marshal(w.tx.Body)
   122  		if err != nil {
   123  			panic(err)
   124  		}
   125  	}
   126  	return w.bodyBz
   127  }
   128  
   129  func (w *wrapper) getAuthInfoBytes() []byte {
   130  	if len(w.authInfoBz) == 0 {
   131  		// if authInfoBz is empty, then marshal the body. authInfoBz will generally
   132  		// be set to nil whenever SetAuthInfo is called so the result of calling
   133  		// this method should always return the correct bytes. Note that after
   134  		// decoding authInfoBz is derived from TxRaw so that it matches what was
   135  		// transmitted over the wire
   136  		var err error
   137  		w.authInfoBz, err = proto.Marshal(w.tx.AuthInfo)
   138  		if err != nil {
   139  			panic(err)
   140  		}
   141  	}
   142  	return w.authInfoBz
   143  }
   144  
   145  func (w *wrapper) initSignersAndMsgsV2() error {
   146  	var err error
   147  	w.signers, w.msgsV2, err = w.tx.GetSigners(w.cdc)
   148  	return err
   149  }
   150  
   151  func (w *wrapper) GetSigners() ([][]byte, error) {
   152  	if w.signers == nil {
   153  		err := w.initSignersAndMsgsV2()
   154  		if err != nil {
   155  			return nil, err
   156  		}
   157  	}
   158  	return w.signers, nil
   159  }
   160  
   161  func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) {
   162  	signerInfos := w.tx.AuthInfo.SignerInfos
   163  	pks := make([]cryptotypes.PubKey, len(signerInfos))
   164  
   165  	for i, si := range signerInfos {
   166  		// NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo.
   167  		// PubKey's can be left unset in SignerInfo.
   168  		if si.PublicKey == nil {
   169  			continue
   170  		}
   171  
   172  		pkAny := si.PublicKey.GetCachedValue()
   173  		pk, ok := pkAny.(cryptotypes.PubKey)
   174  		if ok {
   175  			pks[i] = pk
   176  		} else {
   177  			return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "Expecting PubKey, got: %T", pkAny)
   178  		}
   179  	}
   180  
   181  	return pks, nil
   182  }
   183  
   184  func (w *wrapper) GetGas() uint64 {
   185  	return w.tx.AuthInfo.Fee.GasLimit
   186  }
   187  
   188  func (w *wrapper) GetFee() sdk.Coins {
   189  	return w.tx.AuthInfo.Fee.Amount
   190  }
   191  
   192  func (w *wrapper) FeePayer() []byte {
   193  	feePayer := w.tx.AuthInfo.Fee.Payer
   194  	if feePayer != "" {
   195  		feePayerAddr, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer)
   196  		if err != nil {
   197  			panic(err)
   198  		}
   199  		return feePayerAddr
   200  	}
   201  
   202  	// use first signer as default if no payer specified
   203  	signers, err := w.GetSigners()
   204  	if err != nil {
   205  		return nil
   206  	}
   207  
   208  	return signers[0]
   209  }
   210  
   211  func (w *wrapper) FeeGranter() []byte {
   212  	return w.tx.FeeGranter(w.cdc)
   213  }
   214  
   215  func (w *wrapper) GetMemo() string {
   216  	return w.tx.Body.Memo
   217  }
   218  
   219  // GetTimeoutHeight returns the transaction's timeout height (if set).
   220  func (w *wrapper) GetTimeoutHeight() uint64 {
   221  	return w.tx.Body.TimeoutHeight
   222  }
   223  
   224  func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) {
   225  	signerInfos := w.tx.AuthInfo.SignerInfos
   226  	sigs := w.tx.Signatures
   227  	pubKeys, err := w.GetPubKeys()
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	n := len(signerInfos)
   232  	res := make([]signing.SignatureV2, n)
   233  
   234  	for i, si := range signerInfos {
   235  		// handle nil signatures (in case of simulation)
   236  		if si.ModeInfo == nil {
   237  			res[i] = signing.SignatureV2{
   238  				PubKey: pubKeys[i],
   239  			}
   240  		} else {
   241  			var err error
   242  			sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
   243  			if err != nil {
   244  				return nil, err
   245  			}
   246  			// sequence number is functionally a transaction nonce and referred to as such in the SDK
   247  			nonce := si.GetSequence()
   248  			res[i] = signing.SignatureV2{
   249  				PubKey:   pubKeys[i],
   250  				Data:     sigData,
   251  				Sequence: nonce,
   252  			}
   253  
   254  		}
   255  	}
   256  
   257  	return res, nil
   258  }
   259  
   260  func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error {
   261  	anys, err := tx.SetMsgs(msgs)
   262  	if err != nil {
   263  		return err
   264  	}
   265  
   266  	w.tx.Body.Messages = anys
   267  
   268  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   269  	w.bodyBz = nil
   270  
   271  	// reset signers and msgsV2
   272  	w.signers = nil
   273  	w.msgsV2 = nil
   274  
   275  	return nil
   276  }
   277  
   278  // SetTimeoutHeight sets the transaction's height timeout.
   279  func (w *wrapper) SetTimeoutHeight(height uint64) {
   280  	w.tx.Body.TimeoutHeight = height
   281  
   282  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   283  	w.bodyBz = nil
   284  }
   285  
   286  func (w *wrapper) SetMemo(memo string) {
   287  	w.tx.Body.Memo = memo
   288  
   289  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   290  	w.bodyBz = nil
   291  }
   292  
   293  func (w *wrapper) SetGasLimit(limit uint64) {
   294  	if w.tx.AuthInfo.Fee == nil {
   295  		w.tx.AuthInfo.Fee = &tx.Fee{}
   296  	}
   297  
   298  	w.tx.AuthInfo.Fee.GasLimit = limit
   299  
   300  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   301  	w.authInfoBz = nil
   302  }
   303  
   304  func (w *wrapper) SetFeeAmount(coins sdk.Coins) {
   305  	if w.tx.AuthInfo.Fee == nil {
   306  		w.tx.AuthInfo.Fee = &tx.Fee{}
   307  	}
   308  
   309  	w.tx.AuthInfo.Fee.Amount = coins
   310  
   311  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   312  	w.authInfoBz = nil
   313  }
   314  
   315  func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) {
   316  	if w.tx.AuthInfo.Fee == nil {
   317  		w.tx.AuthInfo.Fee = &tx.Fee{}
   318  	}
   319  
   320  	w.tx.AuthInfo.Fee.Payer = feePayer.String()
   321  
   322  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   323  	w.authInfoBz = nil
   324  }
   325  
   326  func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) {
   327  	if w.tx.AuthInfo.Fee == nil {
   328  		w.tx.AuthInfo.Fee = &tx.Fee{}
   329  	}
   330  
   331  	w.tx.AuthInfo.Fee.Granter = feeGranter.String()
   332  
   333  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   334  	w.authInfoBz = nil
   335  }
   336  
   337  func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error {
   338  	n := len(signatures)
   339  	signerInfos := make([]*tx.SignerInfo, n)
   340  	rawSigs := make([][]byte, n)
   341  
   342  	for i, sig := range signatures {
   343  		var (
   344  			modeInfo *tx.ModeInfo
   345  			pubKey   *codectypes.Any
   346  			err      error
   347  		)
   348  		modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data)
   349  		if sig.PubKey != nil {
   350  			pubKey, err = codectypes.NewAnyWithValue(sig.PubKey)
   351  			if err != nil {
   352  				return err
   353  			}
   354  		}
   355  		signerInfos[i] = &tx.SignerInfo{
   356  			PublicKey: pubKey,
   357  			ModeInfo:  modeInfo,
   358  			Sequence:  sig.Sequence,
   359  		}
   360  	}
   361  
   362  	w.setSignerInfos(signerInfos)
   363  	w.setSignatures(rawSigs)
   364  
   365  	return nil
   366  }
   367  
   368  func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) {
   369  	w.tx.AuthInfo.SignerInfos = infos
   370  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   371  	w.authInfoBz = nil
   372  }
   373  
   374  func (w *wrapper) setSignerInfoAtIndex(index int, info *tx.SignerInfo) {
   375  	signers, err := w.GetSigners()
   376  	if err != nil {
   377  		panic(err)
   378  	}
   379  
   380  	if w.tx.AuthInfo.SignerInfos == nil {
   381  		w.tx.AuthInfo.SignerInfos = make([]*tx.SignerInfo, len(signers))
   382  	}
   383  
   384  	w.tx.AuthInfo.SignerInfos[index] = info
   385  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   386  	w.authInfoBz = nil
   387  }
   388  
   389  func (w *wrapper) setSignatures(sigs [][]byte) {
   390  	w.tx.Signatures = sigs
   391  }
   392  
   393  func (w *wrapper) setSignatureAtIndex(index int, sig []byte) {
   394  	signers, err := w.GetSigners()
   395  	if err != nil {
   396  		panic(err)
   397  	}
   398  
   399  	if w.tx.Signatures == nil {
   400  		w.tx.Signatures = make([][]byte, len(signers))
   401  	}
   402  
   403  	w.tx.Signatures[index] = sig
   404  }
   405  
   406  func (w *wrapper) GetTx() authsigning.Tx {
   407  	return w
   408  }
   409  
   410  func (w *wrapper) GetProtoTx() *tx.Tx {
   411  	return w.tx
   412  }
   413  
   414  // Deprecated: AsAny extracts proto Tx and wraps it into Any.
   415  // NOTE: You should probably use `GetProtoTx` if you want to serialize the transaction.
   416  func (w *wrapper) AsAny() *codectypes.Any {
   417  	return codectypes.UnsafePackAny(w.tx)
   418  }
   419  
   420  // WrapTx creates a TxBuilder wrapper around a tx.Tx proto message.
   421  func WrapTx(protoTx *tx.Tx) client.TxBuilder {
   422  	return &wrapper{
   423  		tx: protoTx,
   424  	}
   425  }
   426  
   427  func (w *wrapper) GetExtensionOptions() []*codectypes.Any {
   428  	return w.tx.Body.ExtensionOptions
   429  }
   430  
   431  func (w *wrapper) GetNonCriticalExtensionOptions() []*codectypes.Any {
   432  	return w.tx.Body.NonCriticalExtensionOptions
   433  }
   434  
   435  func (w *wrapper) SetExtensionOptions(extOpts ...*codectypes.Any) {
   436  	w.tx.Body.ExtensionOptions = extOpts
   437  	w.bodyBz = nil
   438  }
   439  
   440  func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) {
   441  	w.tx.Body.NonCriticalExtensionOptions = extOpts
   442  	w.bodyBz = nil
   443  }
   444  
   445  func (w *wrapper) AddAuxSignerData(data tx.AuxSignerData) error {
   446  	err := data.ValidateBasic()
   447  	if err != nil {
   448  		return err
   449  	}
   450  
   451  	w.bodyBz = data.SignDoc.BodyBytes
   452  
   453  	var body tx.TxBody
   454  	err = w.cdc.Unmarshal(w.bodyBz, &body)
   455  	if err != nil {
   456  		return err
   457  	}
   458  
   459  	if w.tx.Body.Memo != "" && w.tx.Body.Memo != body.Memo {
   460  		return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has memo %s, got %s in AuxSignerData", w.tx.Body.Memo, body.Memo)
   461  	}
   462  	if w.tx.Body.TimeoutHeight != 0 && w.tx.Body.TimeoutHeight != body.TimeoutHeight {
   463  		return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has timeout height %d, got %d in AuxSignerData", w.tx.Body.TimeoutHeight, body.TimeoutHeight)
   464  	}
   465  	if len(w.tx.Body.ExtensionOptions) != 0 {
   466  		if len(w.tx.Body.ExtensionOptions) != len(body.ExtensionOptions) {
   467  			return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d extension options, got %d in AuxSignerData", len(w.tx.Body.ExtensionOptions), len(body.ExtensionOptions))
   468  		}
   469  		for i, o := range w.tx.Body.ExtensionOptions {
   470  			if !o.Equal(body.ExtensionOptions[i]) {
   471  				return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has extension option %+v at index %d, got %+v in AuxSignerData", o, i, body.ExtensionOptions[i])
   472  			}
   473  		}
   474  	}
   475  	if len(w.tx.Body.NonCriticalExtensionOptions) != 0 {
   476  		if len(w.tx.Body.NonCriticalExtensionOptions) != len(body.NonCriticalExtensionOptions) {
   477  			return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d non-critical extension options, got %d in AuxSignerData", len(w.tx.Body.NonCriticalExtensionOptions), len(body.NonCriticalExtensionOptions))
   478  		}
   479  		for i, o := range w.tx.Body.NonCriticalExtensionOptions {
   480  			if !o.Equal(body.NonCriticalExtensionOptions[i]) {
   481  				return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has non-critical extension option %+v at index %d, got %+v in AuxSignerData", o, i, body.NonCriticalExtensionOptions[i])
   482  			}
   483  		}
   484  	}
   485  	if len(w.tx.Body.Messages) != 0 {
   486  		if len(w.tx.Body.Messages) != len(body.Messages) {
   487  			return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has %d Msgs, got %d in AuxSignerData", len(w.tx.Body.Messages), len(body.Messages))
   488  		}
   489  		for i, o := range w.tx.Body.Messages {
   490  			if !o.Equal(body.Messages[i]) {
   491  				return sdkerrors.ErrInvalidRequest.Wrapf("TxBuilder has Msg %+v at index %d, got %+v in AuxSignerData", o, i, body.Messages[i])
   492  			}
   493  		}
   494  	}
   495  
   496  	w.SetMemo(body.Memo)
   497  	w.SetTimeoutHeight(body.TimeoutHeight)
   498  	w.SetExtensionOptions(body.ExtensionOptions...)
   499  	w.SetNonCriticalExtensionOptions(body.NonCriticalExtensionOptions...)
   500  	msgs := make([]sdk.Msg, len(body.Messages))
   501  	for i, msgAny := range body.Messages {
   502  		msgs[i] = msgAny.GetCachedValue().(sdk.Msg)
   503  	}
   504  	err = w.SetMsgs(msgs...)
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	// Get the aux signer's index in GetSigners.
   510  	signerIndex := -1
   511  	signers, err := w.GetSigners()
   512  	if err != nil {
   513  		return err
   514  	}
   515  
   516  	for i, signer := range signers {
   517  		addrBz, err := w.cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(data.Address)
   518  		if err != nil {
   519  			return err
   520  		}
   521  		if bytes.Equal(signer, addrBz) {
   522  			signerIndex = i
   523  		}
   524  	}
   525  	if signerIndex < 0 {
   526  		return sdkerrors.ErrLogic.Wrapf("address %s is not a signer", data.Address)
   527  	}
   528  
   529  	w.setSignerInfoAtIndex(signerIndex, &tx.SignerInfo{
   530  		PublicKey: data.SignDoc.PublicKey,
   531  		ModeInfo:  &tx.ModeInfo{Sum: &tx.ModeInfo_Single_{Single: &tx.ModeInfo_Single{Mode: data.Mode}}},
   532  		Sequence:  data.SignDoc.Sequence,
   533  	})
   534  	w.setSignatureAtIndex(signerIndex, data.Sig)
   535  
   536  	return nil
   537  }