github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/rpc/namespaces/eth/utils.go (about) 1 package eth 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "github.com/ethereum/go-ethereum/common" 8 "github.com/ethereum/go-ethereum/common/hexutil" 9 "github.com/ethereum/go-ethereum/core/vm" 10 ethcrypto "github.com/ethereum/go-ethereum/crypto" 11 ethermint "github.com/fibonacci-chain/fbc/app/types" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server" 13 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 14 sdkerror "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 15 authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported" 16 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/supply" 17 "github.com/fibonacci-chain/fbc/x/evm/types" 18 "github.com/fibonacci-chain/fbc/x/token" 19 "github.com/spf13/viper" 20 "math/big" 21 "strings" 22 ) 23 24 const ( 25 DefaultEVMErrorCode = -32000 26 VMExecuteException = -32015 27 VMExecuteExceptionInEstimate = 3 28 AccountNotExistsCode = 9 29 30 RPCEthCall = "eth_call" 31 RPCEthEstimateGas = "eth_estimateGas" 32 RPCEthGetBlockByHash = "eth_getBlockByHash" 33 34 RPCUnknowErr = "unknow" 35 RPCNullData = "null" 36 ) 37 38 // gasPrice: to get "minimum-gas-prices" config or to get ethermint.DefaultGasPrice 39 func ParseGasPrice() *hexutil.Big { 40 gasPrices, err := sdk.ParseDecCoins(viper.GetString(server.FlagMinGasPrices)) 41 if err == nil && gasPrices != nil && len(gasPrices) > 0 { 42 return (*hexutil.Big)(gasPrices[0].Amount.BigInt()) 43 } 44 45 //return the default gas price : DefaultGasPrice 46 //return the default gas price : DefaultGasPrice 47 defaultGP := sdk.NewDecFromBigIntWithPrec(big.NewInt(ethermint.DefaultGasPrice), sdk.Precision/2+1).BigInt() 48 return (*hexutil.Big)(defaultGP) 49 } 50 51 type cosmosError struct { 52 Code int `json:"code"` 53 Log string `json:"log"` 54 Codespace string `json:"codespace"` 55 } 56 57 func (c cosmosError) Error() string { 58 return c.Log 59 } 60 61 func newCosmosError(code int, log, codeSpace string) cosmosError { 62 return cosmosError{ 63 Code: code, 64 Log: log, 65 Codespace: codeSpace, 66 } 67 } 68 69 func newWrappedCosmosError(code int, log, codeSpace string) cosmosError { 70 e := newCosmosError(code, log, codeSpace) 71 b, _ := json.Marshal(e) 72 e.Log = string(b) 73 return e 74 } 75 76 func parseCosmosError(err error) (*cosmosError, bool) { 77 msg := err.Error() 78 var realErr cosmosError 79 if len(msg) == 0 { 80 return nil, false 81 } 82 if err := json.Unmarshal([]byte(msg), &realErr); err != nil { 83 return nil, false 84 } 85 return &realErr, true 86 } 87 88 type wrappedEthError struct { 89 Wrap ethDataError `json:"0x00000000000000000000000000000000"` 90 } 91 92 type ethDataError struct { 93 Error string `json:"error"` 94 ProgramCounter int `json:"program_counter"` 95 Reason string `json:"reason"` 96 Ret string `json:"return"` 97 } 98 99 type DataError struct { 100 code int `json:"code"` 101 Msg string `json:"msg"` 102 data interface{} `json:"data,omitempty"` 103 } 104 105 func (d DataError) Error() string { 106 return d.Msg 107 } 108 109 func (d DataError) ErrorData() interface{} { 110 return d.data 111 } 112 113 func (d DataError) ErrorCode() int { 114 return d.code 115 } 116 117 func newDataError(revert string, data string) *wrappedEthError { 118 return &wrappedEthError{ 119 Wrap: ethDataError{ 120 Error: "revert", 121 ProgramCounter: 0, 122 Reason: revert, 123 Ret: data, 124 }} 125 } 126 127 func TransformDataError(err error, method string) error { 128 realErr, ok := parseCosmosError(err) 129 if !ok { 130 return DataError{ 131 code: DefaultEVMErrorCode, 132 Msg: err.Error(), 133 data: RPCNullData, 134 } 135 } 136 137 if method == RPCEthGetBlockByHash { 138 return DataError{ 139 code: DefaultEVMErrorCode, 140 Msg: realErr.Error(), 141 data: RPCNullData, 142 } 143 } 144 m, retErr := preProcessError(realErr, err.Error()) 145 if retErr != nil { 146 return realErr 147 } 148 //if there have multi error type of EVM, this need a reactor mode to process error 149 revert, f := m[vm.ErrExecutionReverted.Error()] 150 if !f { 151 revert = RPCUnknowErr 152 } 153 data, f := m[types.ErrorHexData] 154 if !f { 155 data = RPCNullData 156 } 157 switch method { 158 case RPCEthEstimateGas: 159 return DataError{ 160 code: VMExecuteExceptionInEstimate, 161 Msg: revert, 162 data: data, 163 } 164 case RPCEthCall: 165 return DataError{ 166 code: VMExecuteException, 167 Msg: revert, 168 data: newDataError(revert, data), 169 } 170 default: 171 return DataError{ 172 code: DefaultEVMErrorCode, 173 Msg: revert, 174 data: newDataError(revert, data), 175 } 176 } 177 } 178 179 // Preprocess error string, the string of realErr.Log is most like: 180 // `["execution reverted","message","HexData","0x00000000000"];some failed information` 181 // we need marshalled json slice from realErr.Log and using segment tag `[` and `]` to cut it 182 func preProcessError(realErr *cosmosError, origErrorMsg string) (map[string]string, error) { 183 var logs []string 184 lastSeg := strings.LastIndexAny(realErr.Log, "]") 185 if lastSeg < 0 { 186 return nil, DataError{ 187 code: DefaultEVMErrorCode, 188 Msg: origErrorMsg, 189 data: RPCNullData, 190 } 191 } 192 marshaler := realErr.Log[0 : lastSeg+1] 193 e := json.Unmarshal([]byte(marshaler), &logs) 194 if e != nil { 195 return nil, DataError{ 196 code: DefaultEVMErrorCode, 197 Msg: origErrorMsg, 198 data: RPCNullData, 199 } 200 } 201 m := genericStringMap(logs) 202 if m == nil { 203 return nil, DataError{ 204 code: DefaultEVMErrorCode, 205 Msg: origErrorMsg, 206 data: RPCNullData, 207 } 208 } 209 return m, nil 210 } 211 212 func genericStringMap(s []string) map[string]string { 213 var ret = make(map[string]string) 214 if len(s)%2 != 0 { 215 return nil 216 } 217 for i := 0; i < len(s); i += 2 { 218 ret[s[i]] = s[i+1] 219 } 220 return ret 221 } 222 223 func CheckError(txRes sdk.TxResponse) (common.Hash, error) { 224 switch txRes.Code { 225 case sdkerror.ErrTxInMempoolCache.ABCICode(): 226 return common.Hash{}, sdkerror.ErrTxInMempoolCache 227 case sdkerror.ErrMempoolIsFull.ABCICode(): 228 return common.Hash{}, sdkerror.ErrMempoolIsFull 229 case sdkerror.ErrTxTooLarge.ABCICode(): 230 return common.Hash{}, sdkerror.Wrapf(sdkerror.ErrTxTooLarge, txRes.RawLog) 231 } 232 return common.Hash{}, fmt.Errorf(txRes.RawLog) 233 } 234 235 func getStorageByAddressKey(addr common.Address, key []byte) common.Hash { 236 prefix := addr.Bytes() 237 compositeKey := make([]byte, len(prefix)+len(key)) 238 239 copy(compositeKey, prefix) 240 copy(compositeKey[len(prefix):], key) 241 242 return ethcrypto.Keccak256Hash(compositeKey) 243 } 244 245 func accountType(account authexported.Account) token.AccType { 246 switch account.(type) { 247 case *ethermint.EthAccount: 248 if sdk.IsWasmAddress(account.GetAddress()) { 249 return token.WasmAccount 250 } 251 ethAcc, _ := account.(*ethermint.EthAccount) 252 if !bytes.Equal(ethAcc.CodeHash, ethcrypto.Keccak256(nil)) { 253 return token.ContractAccount 254 } 255 return token.UserAccount 256 case *supply.ModuleAccount: 257 return token.ModuleAccount 258 default: 259 return token.OtherAccount 260 } 261 } 262 263 func isAccountNotExistErr(err error) bool { 264 cosmosErr, ok := parseCosmosError(err) 265 if !ok { 266 return false 267 } 268 return cosmosErr.Code == AccountNotExistsCode 269 }