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, ðTx); err == nil { 132 tx = ðTx 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 }