github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/auth/ibc-tx/decoder.go (about)

     1  package ibc_tx
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/unknownproto"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/types"
     9  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    10  	ibctx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/ibc-adapter"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx/signing"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/ibc-tx/internal/adapter"
    13  	"google.golang.org/protobuf/encoding/protowire"
    14  
    15  	//"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/unknownproto"
    16  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    17  
    18  	tx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx"
    19  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    20  )
    21  
    22  func CM40TxDecoder(cdc codec.ProtoCodecMarshaler) func(txBytes []byte) (ibctx.Tx, error) {
    23  	return func(txBytes []byte) (ibctx.Tx, error) {
    24  		// Make sure txBytes follow ADR-027.
    25  		err := rejectNonADR027TxRaw(txBytes)
    26  		if err != nil {
    27  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    28  		}
    29  
    30  		var raw tx.TxRaw
    31  
    32  		// reject all unknown proto fields in the root TxRaw
    33  		err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry())
    34  		if err != nil {
    35  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    36  		}
    37  
    38  		err = cdc.UnmarshalBinaryBare(txBytes, &raw)
    39  		if err != nil {
    40  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    41  		}
    42  
    43  		var body tx.TxBody
    44  		// allow non-critical unknown fields in TxBody
    45  		txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry())
    46  		if err != nil {
    47  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    48  		}
    49  
    50  		err = cdc.UnmarshalBinaryBare(raw.BodyBytes, &body)
    51  		if err != nil {
    52  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    53  		}
    54  
    55  		var authInfo tx.AuthInfo
    56  
    57  		// reject all unknown proto fields in AuthInfo
    58  		err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry())
    59  		if err != nil {
    60  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    61  		}
    62  
    63  		err = cdc.UnmarshalBinaryBare(raw.AuthInfoBytes, &authInfo)
    64  		if err != nil {
    65  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    66  		}
    67  
    68  		ibcTx := &tx.Tx{
    69  			Body:       &body,
    70  			AuthInfo:   &authInfo,
    71  			Signatures: raw.Signatures,
    72  		}
    73  		return &wrapper{
    74  			tx:                           ibcTx,
    75  			bodyBz:                       raw.BodyBytes,
    76  			authInfoBz:                   raw.AuthInfoBytes,
    77  			txBodyHasUnknownNonCriticals: txBodyHasUnknownNonCriticals,
    78  		}, nil
    79  	}
    80  }
    81  
    82  // DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler.
    83  // func IbcTxDecoder(cdc codec.ProtoCodecMarshaler) ibcadapter.TxDecoder {
    84  func IbcTxDecoder(cdc codec.ProtoCodecMarshaler) ibctx.IbcTxDecoder {
    85  	return func(txBytes []byte) (*authtypes.IbcTx, error) {
    86  		// Make sure txBytes follow ADR-027.
    87  		err := rejectNonADR027TxRaw(txBytes)
    88  		if err != nil {
    89  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    90  		}
    91  
    92  		var raw tx.TxRaw
    93  
    94  		// reject all unknown proto fields in the root TxRaw
    95  		err = unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry())
    96  		if err != nil {
    97  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    98  		}
    99  
   100  		err = cdc.UnmarshalBinaryBare(txBytes, &raw)
   101  		if err != nil {
   102  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   103  		}
   104  
   105  		var body tx.TxBody
   106  		// allow non-critical unknown fields in TxBody
   107  		txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry())
   108  		if err != nil {
   109  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   110  		}
   111  
   112  		err = cdc.UnmarshalBinaryBare(raw.BodyBytes, &body)
   113  		if err != nil {
   114  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   115  		}
   116  
   117  		var authInfo tx.AuthInfo
   118  
   119  		// reject all unknown proto fields in AuthInfo
   120  		err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry())
   121  		if err != nil {
   122  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   123  		}
   124  
   125  		err = cdc.UnmarshalBinaryBare(raw.AuthInfoBytes, &authInfo)
   126  		if err != nil {
   127  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   128  		}
   129  
   130  		ibcTx := &tx.Tx{
   131  			Body:       &body,
   132  			AuthInfo:   &authInfo,
   133  			Signatures: raw.Signatures,
   134  		}
   135  		fee, signFee, payer, err := convertFee(authInfo)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  
   140  		signatures := convertSignature(ibcTx)
   141  
   142  		// construct Msg
   143  		stdMsgs, signMsgs, err := constructMsgs(ibcTx)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  
   148  		var signMode []signing.SignMode
   149  		if authInfo.SignerInfos != nil {
   150  			for _, signInfo := range authInfo.SignerInfos {
   151  				modeInfo, ok := signInfo.ModeInfo.Sum.(*tx.ModeInfo_Single_)
   152  				if !ok {
   153  					return nil, sdkerrors.Wrap(sdkerrors.ErrInternal, "only support ModeInfo_Single")
   154  				}
   155  				signMode = append(signMode, modeInfo.Single.Mode)
   156  			}
   157  		}
   158  
   159  		sequences := []uint64{}
   160  		for _, seq := range authInfo.SignerInfos {
   161  			sequences = append(sequences, seq.Sequence)
   162  		}
   163  		hasExtensionOpt := false
   164  		if len(body.ExtensionOptions) != 0 || len(body.NonCriticalExtensionOptions) != 0 {
   165  			hasExtensionOpt = true
   166  		}
   167  
   168  		stx := authtypes.IbcTx{
   169  			&authtypes.StdTx{
   170  				Msgs:       stdMsgs,
   171  				Fee:        fee,
   172  				Signatures: signatures,
   173  				Memo:       ibcTx.Body.Memo,
   174  			},
   175  			raw.AuthInfoBytes,
   176  			raw.BodyBytes,
   177  			signMode,
   178  			signFee,
   179  			signMsgs,
   180  			sequences,
   181  			txBodyHasUnknownNonCriticals,
   182  			hasExtensionOpt,
   183  			payer,
   184  			ValidateParams(ibcTx),
   185  		}
   186  
   187  		return &stx, nil
   188  	}
   189  }
   190  
   191  func ValidateParams(ibcTx *tx.Tx) func() error {
   192  	return func() error {
   193  		if ibcTx.AuthInfo == nil {
   194  			return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "missing AuthInfo")
   195  		}
   196  		if ibcTx.AuthInfo.Fee == nil {
   197  			return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "missing AuthInfo Fee")
   198  		}
   199  		return nil
   200  	}
   201  }
   202  
   203  func constructMsgs(ibcTx *tx.Tx) ([]sdk.Msg, []sdk.Msg, error) {
   204  	var err error
   205  	stdMsgs, signMsgs := []sdk.Msg{}, []sdk.Msg{}
   206  	for _, ibcMsg := range ibcTx.Body.Messages {
   207  		m, ok := ibcMsg.GetCachedValue().(sdk.Msg)
   208  		if !ok {
   209  			return nil, nil, sdkerrors.Wrap(
   210  				sdkerrors.ErrInternal, "messages in ibcTx.Body not implement sdk.Msg",
   211  			)
   212  		}
   213  		var newMsg sdk.Msg
   214  		switch msg := m.(type) {
   215  		case DenomAdapterMsg:
   216  			// ibc transfer fibo is not allowed,should do filter
   217  			newMsg, err = msg.RulesFilter()
   218  			if err != nil {
   219  				return nil, nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "ibc tx decoder not support fibo amount")
   220  			}
   221  		default:
   222  			newMsg = m
   223  		}
   224  		stdMsgs = append(stdMsgs, newMsg)
   225  		signMsgs = append(signMsgs, m)
   226  	}
   227  	return stdMsgs, signMsgs, nil
   228  }
   229  
   230  func convertSignature(ibcTx *tx.Tx) []authtypes.StdSignature {
   231  	ret := make([]authtypes.StdSignature, len(ibcTx.Signatures))
   232  
   233  	for i, s := range ibcTx.Signatures {
   234  		var pkData types.PubKey
   235  		if ibcTx.AuthInfo.SignerInfos != nil {
   236  			var ok bool
   237  			if ibcTx.AuthInfo.SignerInfos[i].PublicKey == nil {
   238  				// maybe it is a simulate request
   239  				ret[i] = authtypes.StdSignature{
   240  					Signature: s,
   241  					PubKey:    nil,
   242  				}
   243  				continue
   244  			}
   245  			pkData, ok = ibcTx.AuthInfo.SignerInfos[i].PublicKey.GetCachedValue().(types.PubKey)
   246  			if !ok {
   247  				return []authtypes.StdSignature{}
   248  			}
   249  		}
   250  		pubKey, err := adapter.ProtoBufPubkey2LagacyPubkey(pkData)
   251  		if err != nil {
   252  			return []authtypes.StdSignature{}
   253  		}
   254  
   255  		ret[i] = authtypes.StdSignature{
   256  			Signature: s,
   257  			PubKey:    pubKey,
   258  		}
   259  	}
   260  
   261  	return ret
   262  }
   263  
   264  func convertFee(authInfo tx.AuthInfo) (authtypes.StdFee, authtypes.IbcFee, string, error) {
   265  
   266  	gaslimit := uint64(0)
   267  	var decCoins sdk.DecCoins
   268  	var err error
   269  	payer := ""
   270  	// for verify signature
   271  	var signFee authtypes.IbcFee
   272  	if authInfo.Fee != nil {
   273  		decCoins, err = feeDenomFilter(authInfo.Fee.Amount)
   274  		if err != nil {
   275  			return authtypes.StdFee{}, authtypes.IbcFee{}, payer, err
   276  		}
   277  		gaslimit = authInfo.Fee.GasLimit
   278  		signFee = authtypes.IbcFee{
   279  			authInfo.Fee.Amount,
   280  			authInfo.Fee.GasLimit,
   281  		}
   282  		payer = authInfo.Fee.Payer
   283  	}
   284  
   285  	return authtypes.StdFee{
   286  		Amount: decCoins,
   287  		Gas:    gaslimit,
   288  	}, signFee, payer, nil
   289  }
   290  
   291  func feeDenomFilter(coins sdk.CoinAdapters) (sdk.DecCoins, error) {
   292  	decCoins := sdk.DecCoins{}
   293  
   294  	if coins != nil {
   295  		for _, fee := range coins {
   296  			amount := fee.Amount.BigInt()
   297  			denom := fee.Denom
   298  			// convert ibc denom to DefaultBondDenom
   299  			if denom == sdk.DefaultIbcWei {
   300  				decCoins = append(decCoins, sdk.DecCoin{
   301  					Denom:  sdk.DefaultBondDenom,
   302  					Amount: sdk.NewDecFromIntWithPrec(sdk.NewIntFromBigInt(amount), sdk.Precision),
   303  				})
   304  			} else {
   305  				// not suport other denom fee
   306  				return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "ibc tx decoder only support wei fee")
   307  			}
   308  		}
   309  	}
   310  	return decCoins, nil
   311  }
   312  
   313  // DefaultJSONTxDecoder returns a default protobuf JSON TxDecoder using the provided Marshaler.
   314  //func DefaultJSONTxDecoder(cdc codec.ProtoCodecMarshaler) sdk.TxDecoder {
   315  //	return func(txBytes []byte) (sdk.Tx, error) {
   316  //		var theTx tx.Tx
   317  //		err := cdc.UnmarshalJSON(txBytes, &theTx)
   318  //		if err != nil {
   319  //			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
   320  //		}
   321  //
   322  //		return &wrapper{
   323  //			tx: &theTx,
   324  //		}, nil
   325  //	}
   326  //}
   327  
   328  // rejectNonADR027TxRaw rejects txBytes that do not follow ADR-027. This is NOT
   329  // a generic ADR-027 checker, it only applies decoding TxRaw. Specifically, it
   330  // only checks that:
   331  // - field numbers are in ascending order (1, 2, and potentially multiple 3s),
   332  // - and varints are as short as possible.
   333  // All other ADR-027 edge cases (e.g. default values) are not applicable with
   334  // TxRaw.
   335  func rejectNonADR027TxRaw(txBytes []byte) error {
   336  	// Make sure all fields are ordered in ascending order with this variable.
   337  	prevTagNum := protowire.Number(0)
   338  
   339  	for len(txBytes) > 0 {
   340  		tagNum, wireType, m := protowire.ConsumeTag(txBytes)
   341  		if m < 0 {
   342  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   343  		}
   344  		// TxRaw only has bytes fields.
   345  		if wireType != protowire.BytesType {
   346  			return fmt.Errorf("expected %d wire type, got %d", protowire.BytesType, wireType)
   347  		}
   348  		// Make sure fields are ordered in ascending order.
   349  		if tagNum < prevTagNum {
   350  			return fmt.Errorf("txRaw must follow ADR-027, got tagNum %d after tagNum %d", tagNum, prevTagNum)
   351  		}
   352  		prevTagNum = tagNum
   353  
   354  		// All 3 fields of TxRaw have wireType == 2, so their next component
   355  		// is a varint, so we can safely call ConsumeVarint here.
   356  		// Byte structure: <varint of bytes length><bytes sequence>
   357  		// Inner  fields are verified in `DefaultTxDecoder`
   358  		lengthPrefix, m := protowire.ConsumeVarint(txBytes[m:])
   359  		if m < 0 {
   360  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   361  		}
   362  		// We make sure that this varint is as short as possible.
   363  		n := varintMinLength(lengthPrefix)
   364  		if n != m {
   365  			return fmt.Errorf("length prefix varint for tagNum %d is not as short as possible, read %d, only need %d", tagNum, m, n)
   366  		}
   367  
   368  		// Skip over the bytes that store fieldNumber and wireType bytes.
   369  		_, _, m = protowire.ConsumeField(txBytes)
   370  		if m < 0 {
   371  			return fmt.Errorf("invalid length; %w", protowire.ParseError(m))
   372  		}
   373  		txBytes = txBytes[m:]
   374  	}
   375  
   376  	return nil
   377  }
   378  
   379  // varintMinLength returns the minimum number of bytes necessary to encode an
   380  // uint using varint encoding.
   381  func varintMinLength(n uint64) int {
   382  	switch {
   383  	// Note: 1<<N == 2**N.
   384  	case n < 1<<(7):
   385  		return 1
   386  	case n < 1<<(7*2):
   387  		return 2
   388  	case n < 1<<(7*3):
   389  		return 3
   390  	case n < 1<<(7*4):
   391  		return 4
   392  	case n < 1<<(7*5):
   393  		return 5
   394  	case n < 1<<(7*6):
   395  		return 6
   396  	case n < 1<<(7*7):
   397  		return 7
   398  	case n < 1<<(7*8):
   399  		return 8
   400  	case n < 1<<(7*9):
   401  		return 9
   402  	default:
   403  		return 10
   404  	}
   405  }