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

     1  package tx
     2  
     3  import (
     4  	"github.com/gogo/protobuf/proto"
     5  
     6  	"github.com/Finschia/finschia-sdk/client"
     7  	codectypes "github.com/Finschia/finschia-sdk/codec/types"
     8  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
     9  	sdk "github.com/Finschia/finschia-sdk/types"
    10  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    11  	"github.com/Finschia/finschia-sdk/types/tx"
    12  	"github.com/Finschia/finschia-sdk/types/tx/signing"
    13  	"github.com/Finschia/finschia-sdk/x/auth/ante"
    14  	authsigning "github.com/Finschia/finschia-sdk/x/auth/signing"
    15  )
    16  
    17  // wrapper is a wrapper around the tx.Tx proto.Message which retain the raw
    18  // body and auth_info bytes.
    19  type wrapper struct {
    20  	tx *tx.Tx
    21  
    22  	// bodyBz represents the protobuf encoding of TxBody. This should be encoding
    23  	// from the client using TxRaw if the tx was decoded from the wire
    24  	bodyBz []byte
    25  
    26  	// authInfoBz represents the protobuf encoding of TxBody. This should be encoding
    27  	// from the client using TxRaw if the tx was decoded from the wire
    28  	authInfoBz []byte
    29  
    30  	txBodyHasUnknownNonCriticals bool
    31  }
    32  
    33  var (
    34  	_ authsigning.Tx             = &wrapper{}
    35  	_ client.TxBuilder           = &wrapper{}
    36  	_ ante.HasExtensionOptionsTx = &wrapper{}
    37  	_ ExtensionOptionsTxBuilder  = &wrapper{}
    38  )
    39  
    40  // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions.
    41  type ExtensionOptionsTxBuilder interface {
    42  	client.TxBuilder
    43  
    44  	SetExtensionOptions(...*codectypes.Any)
    45  	SetNonCriticalExtensionOptions(...*codectypes.Any)
    46  }
    47  
    48  func newBuilder() *wrapper {
    49  	return &wrapper{
    50  		tx: &tx.Tx{
    51  			Body: &tx.TxBody{},
    52  			AuthInfo: &tx.AuthInfo{
    53  				Fee: &tx.Fee{},
    54  			},
    55  		},
    56  	}
    57  }
    58  
    59  func (w *wrapper) GetMsgs() []sdk.Msg {
    60  	return w.tx.GetMsgs()
    61  }
    62  
    63  func (w *wrapper) ValidateBasic() error {
    64  	return w.tx.ValidateBasic()
    65  }
    66  
    67  func (w *wrapper) getBodyBytes() []byte {
    68  	if len(w.bodyBz) == 0 {
    69  		// if bodyBz is empty, then marshal the body. bodyBz will generally
    70  		// be set to nil whenever SetBody is called so the result of calling
    71  		// this method should always return the correct bytes. Note that after
    72  		// decoding bodyBz is derived from TxRaw so that it matches what was
    73  		// transmitted over the wire
    74  		var err error
    75  		w.bodyBz, err = proto.Marshal(w.tx.Body)
    76  		if err != nil {
    77  			panic(err)
    78  		}
    79  	}
    80  	return w.bodyBz
    81  }
    82  
    83  func (w *wrapper) getAuthInfoBytes() []byte {
    84  	if len(w.authInfoBz) == 0 {
    85  		// if authInfoBz is empty, then marshal the body. authInfoBz will generally
    86  		// be set to nil whenever SetAuthInfo is called so the result of calling
    87  		// this method should always return the correct bytes. Note that after
    88  		// decoding authInfoBz is derived from TxRaw so that it matches what was
    89  		// transmitted over the wire
    90  		var err error
    91  		w.authInfoBz, err = proto.Marshal(w.tx.AuthInfo)
    92  		if err != nil {
    93  			panic(err)
    94  		}
    95  	}
    96  	return w.authInfoBz
    97  }
    98  
    99  func (w *wrapper) GetSigners() []sdk.AccAddress {
   100  	return w.tx.GetSigners()
   101  }
   102  
   103  func (w *wrapper) GetPubKeys() ([]cryptotypes.PubKey, error) {
   104  	signerInfos := w.tx.AuthInfo.SignerInfos
   105  	pks := make([]cryptotypes.PubKey, len(signerInfos))
   106  
   107  	for i, si := range signerInfos {
   108  		// NOTE: it is okay to leave this nil if there is no PubKey in the SignerInfo.
   109  		// PubKey's can be left unset in SignerInfo.
   110  		if si.PublicKey == nil {
   111  			continue
   112  		}
   113  
   114  		pkAny := si.PublicKey.GetCachedValue()
   115  		pk, ok := pkAny.(cryptotypes.PubKey)
   116  		if ok {
   117  			pks[i] = pk
   118  		} else {
   119  			return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "Expecting PubKey, got: %T", pkAny)
   120  		}
   121  	}
   122  
   123  	return pks, nil
   124  }
   125  
   126  func (w *wrapper) GetGas() uint64 {
   127  	return w.tx.AuthInfo.Fee.GasLimit
   128  }
   129  
   130  func (w *wrapper) GetFee() sdk.Coins {
   131  	return w.tx.AuthInfo.Fee.Amount
   132  }
   133  
   134  func (w *wrapper) FeePayer() sdk.AccAddress {
   135  	feePayer := w.tx.AuthInfo.Fee.Payer
   136  	if feePayer != "" {
   137  		return sdk.MustAccAddressFromBech32(feePayer)
   138  	}
   139  	// use first signer as default if no payer specified
   140  	return w.GetSigners()[0]
   141  }
   142  
   143  func (w *wrapper) FeeGranter() sdk.AccAddress {
   144  	feePayer := w.tx.AuthInfo.Fee.Granter
   145  	if feePayer != "" {
   146  		return sdk.MustAccAddressFromBech32(feePayer)
   147  	}
   148  	return nil
   149  }
   150  
   151  func (w *wrapper) GetMemo() string {
   152  	return w.tx.Body.Memo
   153  }
   154  
   155  // GetTimeoutHeight returns the transaction's timeout height (if set).
   156  func (w *wrapper) GetTimeoutHeight() uint64 {
   157  	return w.tx.Body.TimeoutHeight
   158  }
   159  
   160  func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) {
   161  	signerInfos := w.tx.AuthInfo.SignerInfos
   162  	sigs := w.tx.Signatures
   163  	pubKeys, err := w.GetPubKeys()
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	n := len(signerInfos)
   168  	res := make([]signing.SignatureV2, n)
   169  
   170  	for i, si := range signerInfos {
   171  		// handle nil signatures (in case of simulation)
   172  		if si.ModeInfo == nil {
   173  			res[i] = signing.SignatureV2{
   174  				PubKey: pubKeys[i],
   175  			}
   176  		} else {
   177  			var err error
   178  			sigData, err := ModeInfoAndSigToSignatureData(si.ModeInfo, sigs[i])
   179  			if err != nil {
   180  				return nil, err
   181  			}
   182  			res[i] = signing.SignatureV2{
   183  				PubKey:   pubKeys[i],
   184  				Data:     sigData,
   185  				Sequence: si.GetSequence(),
   186  			}
   187  
   188  		}
   189  	}
   190  
   191  	return res, nil
   192  }
   193  
   194  func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error {
   195  	anys := make([]*codectypes.Any, len(msgs))
   196  
   197  	for i, msg := range msgs {
   198  		var err error
   199  		anys[i], err = codectypes.NewAnyWithValue(msg)
   200  		if err != nil {
   201  			return err
   202  		}
   203  	}
   204  
   205  	w.tx.Body.Messages = anys
   206  
   207  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   208  	w.bodyBz = nil
   209  
   210  	return nil
   211  }
   212  
   213  // SetTimeoutHeight sets the transaction's height timeout.
   214  func (w *wrapper) SetTimeoutHeight(height uint64) {
   215  	w.tx.Body.TimeoutHeight = height
   216  
   217  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   218  	w.bodyBz = nil
   219  }
   220  
   221  func (w *wrapper) SetMemo(memo string) {
   222  	w.tx.Body.Memo = memo
   223  
   224  	// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
   225  	w.bodyBz = nil
   226  }
   227  
   228  func (w *wrapper) SetGasLimit(limit uint64) {
   229  	if w.tx.AuthInfo.Fee == nil {
   230  		w.tx.AuthInfo.Fee = &tx.Fee{}
   231  	}
   232  
   233  	w.tx.AuthInfo.Fee.GasLimit = limit
   234  
   235  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   236  	w.authInfoBz = nil
   237  }
   238  
   239  func (w *wrapper) SetFeeAmount(coins sdk.Coins) {
   240  	if w.tx.AuthInfo.Fee == nil {
   241  		w.tx.AuthInfo.Fee = &tx.Fee{}
   242  	}
   243  
   244  	w.tx.AuthInfo.Fee.Amount = coins
   245  
   246  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   247  	w.authInfoBz = nil
   248  }
   249  
   250  func (w *wrapper) SetFeePayer(feePayer sdk.AccAddress) {
   251  	if w.tx.AuthInfo.Fee == nil {
   252  		w.tx.AuthInfo.Fee = &tx.Fee{}
   253  	}
   254  
   255  	w.tx.AuthInfo.Fee.Payer = feePayer.String()
   256  
   257  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   258  	w.authInfoBz = nil
   259  }
   260  
   261  func (w *wrapper) SetFeeGranter(feeGranter sdk.AccAddress) {
   262  	if w.tx.AuthInfo.Fee == nil {
   263  		w.tx.AuthInfo.Fee = &tx.Fee{}
   264  	}
   265  
   266  	w.tx.AuthInfo.Fee.Granter = feeGranter.String()
   267  
   268  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   269  	w.authInfoBz = nil
   270  }
   271  
   272  func (w *wrapper) SetSignatures(signatures ...signing.SignatureV2) error {
   273  	n := len(signatures)
   274  	signerInfos := make([]*tx.SignerInfo, n)
   275  	rawSigs := make([][]byte, n)
   276  
   277  	for i, sig := range signatures {
   278  		var modeInfo *tx.ModeInfo
   279  		modeInfo, rawSigs[i] = SignatureDataToModeInfoAndSig(sig.Data)
   280  		any, err := codectypes.NewAnyWithValue(sig.PubKey)
   281  		if err != nil {
   282  			return err
   283  		}
   284  		signerInfos[i] = &tx.SignerInfo{
   285  			PublicKey: any,
   286  			ModeInfo:  modeInfo,
   287  			Sequence:  sig.Sequence,
   288  		}
   289  	}
   290  
   291  	w.setSignerInfos(signerInfos)
   292  	w.setSignatures(rawSigs)
   293  
   294  	return nil
   295  }
   296  
   297  func (w *wrapper) setSignerInfos(infos []*tx.SignerInfo) {
   298  	w.tx.AuthInfo.SignerInfos = infos
   299  	// set authInfoBz to nil because the cached authInfoBz no longer matches tx.AuthInfo
   300  	w.authInfoBz = nil
   301  }
   302  
   303  func (w *wrapper) setSignatures(sigs [][]byte) {
   304  	w.tx.Signatures = sigs
   305  }
   306  
   307  func (w *wrapper) GetTx() authsigning.Tx {
   308  	return w
   309  }
   310  
   311  func (w *wrapper) GetProtoTx() *tx.Tx {
   312  	return w.tx
   313  }
   314  
   315  // Deprecated: AsAny extracts proto Tx and wraps it into Any.
   316  // NOTE: You should probably use `GetProtoTx` if you want to serialize the transaction.
   317  func (w *wrapper) AsAny() *codectypes.Any {
   318  	return codectypes.UnsafePackAny(w.tx)
   319  }
   320  
   321  // WrapTx creates a TxBuilder wrapper around a tx.Tx proto message.
   322  func WrapTx(protoTx *tx.Tx) client.TxBuilder {
   323  	return &wrapper{
   324  		tx: protoTx,
   325  	}
   326  }
   327  
   328  func (w *wrapper) GetExtensionOptions() []*codectypes.Any {
   329  	return w.tx.Body.ExtensionOptions
   330  }
   331  
   332  func (w *wrapper) GetNonCriticalExtensionOptions() []*codectypes.Any {
   333  	return w.tx.Body.NonCriticalExtensionOptions
   334  }
   335  
   336  func (w *wrapper) SetExtensionOptions(extOpts ...*codectypes.Any) {
   337  	w.tx.Body.ExtensionOptions = extOpts
   338  	w.bodyBz = nil
   339  }
   340  
   341  func (w *wrapper) SetNonCriticalExtensionOptions(extOpts ...*codectypes.Any) {
   342  	w.tx.Body.NonCriticalExtensionOptions = extOpts
   343  	w.bodyBz = nil
   344  }