From d77770d96ea72a04ca4621e0516938648a3bac0d Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 26 May 2020 13:02:33 +0200 Subject: [PATCH] rpc: internal/ethapi: added custom error types --- console/bridge.go | 2 ++ internal/ethapi/api.go | 28 ++++++++++++++++++++++++++-- rpc/json.go | 4 ++++ rpc/types.go | 6 ++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/console/bridge.go b/console/bridge.go index ace8aeeba0..436db6ca5b 100644 --- a/console/bridge.go +++ b/console/bridge.go @@ -435,6 +435,8 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) { } case rpc.Error: setError(resp, err.ErrorCode(), err.Error()) + case rpc.DataError: + resp.Set("error", map[string]interface{}{"code": -32603, "message": err.Error(), "data": err.ErrorData()}) default: setError(resp, -32603, err.Error()) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0a25cdc70c..28aec5228c 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -864,6 +864,21 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo return result, err } +var _ rpc.DataError = (*revertError)(nil) + +type revertError struct { + err string // The error string + errData interface{} // additional data +} + +func (e revertError) Error() string { + return e.err +} + +func (e revertError) ErrorData() interface{} { + return e.errData +} + // Call executes the given transaction on the state for the given block number. // // Additionally, the caller can specify a batch of contract for fields overriding. @@ -883,12 +898,17 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr if len(result.Revert()) > 0 { reason, err := abi.UnpackRevert(result.Revert()) if err == nil { - return nil, fmt.Errorf("execution reverted: %v", reason) + return nil, &revertError{ + err: "execution reverted", + errData: reason, + } } } - return result.Return(), nil + return result.Return(), result.Err } +var _ rpc.DataError = (*estimateGasError)(nil) + type estimateGasError struct { error string // Concrete error type if it's failed to estimate gas usage vmerr error // Additional field, it's non-nil if the given transaction is invalid @@ -906,6 +926,10 @@ func (e estimateGasError) Error() string { return errMsg } +func (e estimateGasError) ErrorData() interface{} { + return e.revert +} + func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap *big.Int) (hexutil.Uint64, error) { // Binary search the gas requirement, as it may be higher than the amount used var ( diff --git a/rpc/json.go b/rpc/json.go index 61631a3d76..5b48e01e67 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -115,6 +115,10 @@ func errorMessage(err error) *jsonrpcMessage { if ok { msg.Error.Code = ec.ErrorCode() } + de, ok := err.(DataError) + if ok { + msg.Error.Data = de.ErrorData() + } return msg } diff --git a/rpc/types.go b/rpc/types.go index dc9248d0fe..bab1b3957b 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -41,6 +41,12 @@ type Error interface { ErrorCode() int // returns the code } +// A DataError contains some data in addition to the error message. +type DataError interface { + Error() string // returns the message + ErrorData() interface{} // returns the error data +} + // ServerCodec implements reading, parsing and writing RPC messages for the server side of // a RPC session. Implementations must be go-routine safe since the codec can be called in // multiple go-routines concurrently.