refine err codes

This commit is contained in:
brion 2022-12-28 20:14:52 +08:00
parent 00829e5e35
commit 8028f6499f

View file

@ -48,17 +48,23 @@ const (
singleCallTimeout = 1 * time.Second singleCallTimeout = 1 * time.Second
multiCallLimit = 50 multiCallLimit = 50
errParam = -40001 // client param error
errConsensus = -40002 // error on consensus check errCodeTxArgs = -40000
errLogic = -40003 // logic error errNativeMethodNotFound = -40001
errEVM = -40004 // error on evm execution errNativeMethodInput = -40002
errNativeMethodInputAddress = -40003
// evm processing error
errNativeMethodOutput = -40010
errNativeMethodStateError = -40011
errMessageExecuting = -40012
errEVMCancelled = -40013
errEVMReverted = -40014
) )
var ( var (
ethMultiCallCacheHit = metrics.GetOrRegisterMeter("rpc/ethmulticall/cache/hit", nil) ethMultiCallCacheHit = metrics.GetOrRegisterMeter("rpc/ethmulticall/cache/hit", nil)
ethMultiCallCacheCount = metrics.GetOrRegisterMeter("rpc/ethmulticall/cache/count", nil) ethMultiCallCacheCount = metrics.GetOrRegisterMeter("rpc/ethmulticall/cache/count", nil)
errCancelled = fmt.Errorf("execution aborted (timeout = %v)", singleCallTimeout)
) )
const ( const (
@ -131,39 +137,51 @@ func ethCallCacheKey(b Backend, blockHash common.Hash, to *common.Address, input
return sb.String() return sb.String()
} }
func handleNative(ctx context.Context, state *state.StateDB, msg types.Message) ([]byte, error) { func handleNative(ctx context.Context, state *state.StateDB, msg types.Message) ([]byte, int, error) {
data := msg.Data() data := msg.Data()
method, err := erc20ABI.MethodById(data) method, err := erc20ABI.MethodById(data)
if err != nil { if err != nil {
return nil, err return nil, errNativeMethodNotFound, err
} }
switch method.Name { switch method.Name {
case "name", "symbol": case "name", "symbol":
return method.Outputs.Pack("ETH") res, err := method.Outputs.Pack("ETH")
case "decimals": if err != nil {
return method.Outputs.Pack(uint8(18)) return nil, errNativeMethodOutput, err
case "totalSupply":
return method.Outputs.Pack(big.NewInt(1_000_000_000_000_000_000)) // 1 ETH
} }
return res, 0, nil
if method.Name == "balanceOf" { case "decimals":
res, err := method.Outputs.Pack(uint8(18))
if err != nil {
return nil, errNativeMethodOutput, err
}
return res, 0, nil
case "totalSupply":
res, err := method.Outputs.Pack(big.NewInt(1_000_000_000_000_000_000)) // 1 ETH
if err != nil {
return nil, errNativeMethodOutput, err
}
return res, 0, nil
case "balanceOf":
inputs, err := method.Inputs.Unpack(data[4:]) inputs, err := method.Inputs.Unpack(data[4:])
if err != nil || len(inputs) == 0 { if err != nil || len(inputs) == 0 {
return nil, fmt.Errorf("input error") return nil, errNativeMethodInput, err
} }
address, ok := inputs[0].(common.Address) address, ok := inputs[0].(common.Address)
if !ok { if !ok {
return nil, fmt.Errorf("input address parse error") return nil, errNativeMethodInputAddress, fmt.Errorf("input address error")
} }
balance, err := method.Outputs.Pack(state.GetBalance(address)) balance, err := method.Outputs.Pack(state.GetBalance(address))
if err != nil { if err != nil {
return nil, err return nil, errNativeMethodOutput, err
} }
return balance, state.Error() if state.Error() != nil {
return nil, errNativeMethodStateError, state.Error()
}
return balance, 0, nil
default:
return nil, errNativeMethodNotFound, fmt.Errorf("method not found")
} }
// should never reach here
return nil, fmt.Errorf("unsupported method")
} }
func doOneCall(ctx context.Context, b Backend, state *state.StateDB, header *types.Header, arg TransactionArgs, disableCache bool) (*callResult, error) { func doOneCall(ctx context.Context, b Backend, state *state.StateDB, header *types.Header, arg TransactionArgs, disableCache bool) (*callResult, error) {
@ -198,18 +216,19 @@ func doOneCall(ctx context.Context, b Backend, state *state.StateDB, header *typ
msg, err := arg.ToMessage(b.RPCGasCap(), header.BaseFee) msg, err := arg.ToMessage(b.RPCGasCap(), header.BaseFee)
if err != nil { if err != nil {
result.Code = errParam result.Code = errCodeTxArgs
result.Err = err.Error() result.Err = err.Error()
return result, err return result, err
} }
// skip EVM if requests for native token // skip EVM if requests for native token
if strings.ToLower(msg.To().Hex()) == nativeAddr { if strings.ToLower(msg.To().Hex()) == nativeAddr {
result.Result, err = handleNative(ctx, state, msg) res, code, err := handleNative(ctx, state, msg)
if err != nil { if err != nil {
result.Code = errLogic result.Code = code
result.Err = err.Error() result.Err = err.Error()
} }
result.Result = res
return result, err return result, err
} }
@ -226,16 +245,15 @@ func doOneCall(ctx context.Context, b Backend, state *state.StateDB, header *typ
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
evmRet, err := core.ApplyMessage(evm, msg, gp) evmRet, err := core.ApplyMessage(evm, msg, gp)
if err != nil { if err != nil {
result.Code = errConsensus result.Code = errMessageExecuting
result.Err = err.Error() result.Err = err.Error()
return result, err return result, err
} }
// If the timer caused an abort, return an appropriate error message // If the timer caused an abort, return an appropriate error message
if evm.Cancelled() { if evm.Cancelled() {
err = errCancelled result.Code = errEVMCancelled
result.Code = errLogic result.Err = fmt.Sprintf("execution cancelled, either fast failed or exceeding timeout(%v)", singleCallTimeout)
result.Err = err.Error()
return result, err return result, err
} }
@ -244,7 +262,7 @@ func doOneCall(ctx context.Context, b Backend, state *state.StateDB, header *typ
if len(evmRet.Revert()) > 0 { if len(evmRet.Revert()) > 0 {
e = newRevertError(evmRet) e = newRevertError(evmRet)
} }
result.Code = errEVM result.Code = errEVMReverted
result.Err = e.Error() result.Err = e.Error()
return result, e return result, e
} }