github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/decoder.go (about)

     1  package types
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    10  	typestx "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/tx"
    11  	ibctxdecoder "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/ibc-tx"
    12  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    13  	"github.com/fibonacci-chain/fbc/libs/tendermint/global"
    14  	"github.com/fibonacci-chain/fbc/libs/tendermint/types"
    15  	"github.com/golang/protobuf/proto"
    16  )
    17  
    18  const IGNORE_HEIGHT_CHECKING = -1
    19  
    20  // evmDecoder:  MsgEthereumTx decoder by Ethereum RLP
    21  // ubruDecoder: customized unmarshalling implemented by UnmarshalFromAmino. higher performance!
    22  // ubDecoder:   The original amino decoder, decoding by reflection
    23  // ibcDecoder:  Protobuf decoder
    24  
    25  // When and which decoder decoding what kind of tx:
    26  // | ------------| --------------------|---------------|-------------|-----------------|----------------|
    27  // |             | Before ubruDecoder  | Before Venus  | After Venus | Before VenusOne | After VenusOne |
    28  // |             | carried out         |               |             |                 |                |
    29  // | ------------|---------------------|---------------|-------------|-----------------|----------------|
    30  // | evmDecoder  |                     |               |    evmtx    |   evmtx         |   evmtx        |
    31  // | ubruDecoder |                     | stdtx & evmtx |    stdtx    |   stdtx         |   stdtx        |
    32  // | ubDecoder   | stdtx,evmtx,otherTx | otherTx       |    otherTx  |   otherTx       |   otherTx      |
    33  // | ibcDecoder  |                     |               |             |                 |   ibcTx        |
    34  // | ------------| --------------------|---------------|-------------|-----------------|----------------|
    35  
    36  func TxDecoder(cdc codec.CdcAbstraction) sdk.TxDecoder {
    37  
    38  	return func(txBytes []byte, heights ...int64) (sdk.Tx, error) {
    39  		if len(heights) > 1 {
    40  			return nil, fmt.Errorf("to many height parameters")
    41  		}
    42  		var tx sdk.Tx
    43  		var err error
    44  		if len(txBytes) == 0 {
    45  			return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty")
    46  		}
    47  
    48  		var height int64
    49  		if len(heights) == 1 {
    50  			height = heights[0]
    51  		} else {
    52  			height = global.GetGlobalHeight()
    53  		}
    54  
    55  		for index, f := range []decodeFunc{
    56  			evmDecoder,
    57  			ubruDecoder,
    58  			ubDecoder,
    59  			ibcDecoder,
    60  		} {
    61  			if tx, err = f(cdc, txBytes, height); err == nil {
    62  				tx.SetRaw(txBytes)
    63  				tx.SetTxHash(types.Tx(txBytes).Hash(height))
    64  				// index=0 means it is a evmtx(evmDecoder) ,we wont verify again
    65  				// height > IGNORE_HEIGHT_CHECKING means it is a query request
    66  				if index > 0 && height > IGNORE_HEIGHT_CHECKING {
    67  					if sensitive, ok := tx.(sdk.HeightSensitive); ok {
    68  						if err := sensitive.ValidWithHeight(height); err != nil {
    69  							return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    70  						}
    71  					}
    72  				}
    73  
    74  				return tx, nil
    75  			}
    76  		}
    77  
    78  		return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
    79  	}
    80  }
    81  
    82  // Unmarshaler is a generic type for Unmarshal functions
    83  type Unmarshaler func(bytes []byte, ptr interface{}) error
    84  
    85  func ibcDecoder(cdcWrapper codec.CdcAbstraction, bytes []byte, height int64) (tx sdk.Tx, err error) {
    86  	if height >= 0 && !types.HigherThanVenus1(height) {
    87  		err = fmt.Errorf("IbcTxDecoder decode tx err,lower than Venus1 height")
    88  		return
    89  	}
    90  	simReq := &typestx.SimulateRequest{}
    91  	txBytes := bytes
    92  
    93  	err = simReq.Unmarshal(bytes)
    94  	if err == nil && simReq.Tx != nil {
    95  		txBytes, err = proto.Marshal(simReq.Tx)
    96  		if err != nil {
    97  			return nil, fmt.Errorf("relayTx invalid tx Marshal err %v", err)
    98  		}
    99  	}
   100  
   101  	if txBytes == nil {
   102  		return nil, errors.New("relayTx empty txBytes is not allowed")
   103  	}
   104  
   105  	cdc, ok := cdcWrapper.(*codec.CodecProxy)
   106  	if !ok {
   107  		return nil, errors.New("Invalid cdc abstraction!")
   108  	}
   109  	marshaler := cdc.GetProtocMarshal()
   110  	decode := ibctxdecoder.IbcTxDecoder(marshaler)
   111  	tx, err = decode(txBytes)
   112  	if err != nil {
   113  		return nil, fmt.Errorf("IbcTxDecoder decode tx err %v", err)
   114  	}
   115  
   116  	return
   117  }
   118  
   119  type decodeFunc func(codec.CdcAbstraction, []byte, int64) (sdk.Tx, error)
   120  
   121  // 1. Try to decode as MsgEthereumTx by RLP
   122  func evmDecoder(_ codec.CdcAbstraction, txBytes []byte, height int64) (tx sdk.Tx, err error) {
   123  
   124  	// bypass height checking in case of a negative number
   125  	if height >= 0 && !types.HigherThanVenus(height) {
   126  		err = fmt.Errorf("lower than Venus")
   127  		return
   128  	}
   129  
   130  	var ethTx MsgEthereumTx
   131  	if err = authtypes.EthereumTxDecode(txBytes, &ethTx); err == nil {
   132  		tx = &ethTx
   133  	}
   134  	return
   135  }
   136  
   137  // 2. try customized unmarshalling implemented by UnmarshalFromAmino. higher performance!
   138  func ubruDecoder(cdc codec.CdcAbstraction, txBytes []byte, height int64) (tx sdk.Tx, err error) {
   139  	var v interface{}
   140  	if v, err = cdc.UnmarshalBinaryLengthPrefixedWithRegisteredUbmarshaller(txBytes, &tx); err != nil {
   141  		return nil, err
   142  	}
   143  	return sanityCheck(v.(sdk.Tx), height)
   144  }
   145  
   146  // TODO: switch to UnmarshalBinaryBare on SDK v0.40.0
   147  // 3. the original amino way, decode by reflection.
   148  func ubDecoder(cdc codec.CdcAbstraction, txBytes []byte, height int64) (tx sdk.Tx, err error) {
   149  	err = cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	return sanityCheck(tx, height)
   154  }
   155  
   156  func sanityCheck(tx sdk.Tx, height int64) (sdk.Tx, error) {
   157  	if tx.GetType() == sdk.EvmTxType && types.HigherThanVenus(height) {
   158  		return nil, fmt.Errorf("amino decode is not allowed for MsgEthereumTx")
   159  	}
   160  	return tx, nil
   161  }