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  }