Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpc: remove Cause field from RPC error #2544

Merged
merged 5 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 69 additions & 43 deletions pkg/rpc/response/errors.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
package response

import (
"errors"
"fmt"
"net/http"
)

type (
// Error object for outputting JSON-RPC 2.0
// errors.
Error struct {
Code int64 `json:"code"`
HTTPCode int `json:"-"`
Cause error `json:"-"`
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
Message string `json:"message"`
Data string `json:"data,omitempty"`
}
// Error represents JSON-RPC 2.0 error type.
type Error struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data string `json:"data,omitempty"`
}

// Standard RPC error codes defined by the JSON-RPC 2.0 specification.
const (
// InternalServerErrorCode is returned for internal RPC server error.
InternalServerErrorCode = -32603
// BadRequestCode is returned on parse error.
BadRequestCode = -32700
// InvalidRequestCode is returned on invalid request.
InvalidRequestCode = -32600
// MethodNotFoundCode is returned on unknown method calling.
MethodNotFoundCode = -32601
// InvalidParamsCode is returned on request with invalid params.
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
InvalidParamsCode = -32602
)

// InternalServerErrorCode is returned for internal RPC server error.
const InternalServerErrorCode = -32603
// RPC error codes defined by the Neo JSON-RPC specification extension.
const (
// RPCErrorCode is returned on RPC request processing error.
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
RPCErrorCode = -100
)

var (
// ErrInvalidParams represents a generic 'invalid parameters' error.
ErrInvalidParams = NewInvalidParamsError("", errors.New("invalid params"))
ErrInvalidParams = NewInvalidParamsError("invalid params")
// ErrUnknownBlock is returned if requested block is not found.
ErrUnknownBlock = NewError(RPCErrorCode, "Unknown block", "")
// ErrUnknownTransaction is returned if requested transaction is not found.
ErrUnknownTransaction = NewError(RPCErrorCode, "Unknown transaction", "")
// ErrUnknownHeader is returned when requested header is not found.
ErrUnknownHeader = NewError(RPCErrorCode, "Unknown header", "")
// ErrUnknownScriptContainer is returned when requested block or transaction is not found.
ErrUnknownScriptContainer = NewError(RPCErrorCode, "Unknown script container", "")
// ErrUnknownStateRoot is returned when requested state root is not found.
ErrUnknownStateRoot = NewError(RPCErrorCode, "Unknown state root", "")
// ErrAlreadyExists represents SubmitError with code -501.
ErrAlreadyExists = NewSubmitError(-501, "Block or transaction already exists and cannot be sent repeatedly.")
// ErrOutOfMemory represents SubmitError with code -502.
Expand All @@ -38,70 +58,76 @@ var (
ErrUnknown = NewSubmitError(-500, "Unknown error.")
)
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved

// NewError is an Error constructor that takes Error contents from its
// parameters.
func NewError(code int64, httpCode int, message string, data string, cause error) *Error {
// NewError is an Error constructor that takes Error contents from its parameters.
func NewError(code int64, message string, data string) *Error {
return &Error{
Code: code,
HTTPCode: httpCode,
Cause: cause,
Message: message,
Data: data,
Code: code,
Message: message,
Data: data,
}
}

// NewParseError creates a new error with code
// -32700.
func NewParseError(data string, cause error) *Error {
return NewError(-32700, http.StatusBadRequest, "Parse Error", data, cause)
func NewParseError(data string) *Error {
return NewError(BadRequestCode, "Parse Error", data)
}

// NewInvalidRequestError creates a new error with
// code -32600.
func NewInvalidRequestError(data string, cause error) *Error {
return NewError(-32600, http.StatusUnprocessableEntity, "Invalid Request", data, cause)
func NewInvalidRequestError(data string) *Error {
return NewError(InvalidRequestCode, "Invalid Request", data)
}

// NewMethodNotFoundError creates a new error with
// code -32601.
func NewMethodNotFoundError(data string, cause error) *Error {
return NewError(-32601, http.StatusMethodNotAllowed, "Method not found", data, cause)
func NewMethodNotFoundError(data string) *Error {
return NewError(MethodNotFoundCode, "Method not found", data)
}

// NewInvalidParamsError creates a new error with
// code -32602.
func NewInvalidParamsError(data string, cause error) *Error {
return NewError(-32602, http.StatusUnprocessableEntity, "Invalid Params", data, cause)
func NewInvalidParamsError(data string) *Error {
return NewError(InvalidParamsCode, "Invalid Params", data)
}

// NewInternalServerError creates a new error with
// code -32603.
func NewInternalServerError(data string, cause error) *Error {
return NewError(InternalServerErrorCode, http.StatusInternalServerError, "Internal error", data, cause)
func NewInternalServerError(data string) *Error {
return NewError(InternalServerErrorCode, "Internal error", data)
}

// NewRPCError creates a new error with
// code -100.
func NewRPCError(message string, data string, cause error) *Error {
return NewError(-100, http.StatusUnprocessableEntity, message, data, cause)
func NewRPCError(message string, data string) *Error {
return NewError(RPCErrorCode, message, data)
}

// NewSubmitError creates a new error with
// specified error code and error message.
func NewSubmitError(code int64, message string) *Error {
return NewError(code, http.StatusUnprocessableEntity, message, "", nil)
return NewError(code, message, "")
}

// WrapErrorWithData returns copy of the given error with the specified data and cause.
// It does not modify the source error.
func WrapErrorWithData(e *Error, data string) *Error {
return NewError(e.Code, e.Message, data)
}

// Error implements the error interface.
func (e *Error) Error() string {
if e.Cause == nil {
return fmt.Sprintf("%s (%d) - %s", e.Message, e.Code, e.Data)
if len(e.Data) == 0 {
return fmt.Sprintf("%s (%d)", e.Message, e.Code)
}
return fmt.Sprintf("%s (%d) - %s - %s", e.Message, e.Code, e.Data, e.Cause)
return fmt.Sprintf("%s (%d) - %s", e.Message, e.Code, e.Data)
}

// WrapErrorWithData returns copy of the given error with the specified data and cause.
// It does not modify the source error.
func WrapErrorWithData(e *Error, data error) *Error {
return NewError(e.Code, e.HTTPCode, e.Message, data.Error(), data)
// Is denotes whether the error matches the target one.
func (e *Error) Is(target error) bool {
clTarget, ok := target.(*Error)
if !ok {
return false
}
return e.Code == clTarget.Code
}
32 changes: 0 additions & 32 deletions pkg/rpc/response/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,6 @@ type Raw struct {
Result json.RawMessage `json:"result,omitempty"`
}

// AbstractResult is an interface which represents either single JSON-RPC 2.0 response
// or batch JSON-RPC 2.0 response.
type AbstractResult interface {
RunForErrors(f func(jsonErr *Error))
}

// Abstract represents abstract JSON-RPC 2.0 response, it differs from Raw in
// that Result field is an interface here.
type Abstract struct {
HeaderAndError
Result interface{} `json:"result,omitempty"`
}

// RunForErrors implements AbstractResult interface.
func (a Abstract) RunForErrors(f func(jsonErr *Error)) {
if a.Error != nil {
f(a.Error)
}
}

// AbstractBatch represents abstract JSON-RPC 2.0 batch-response.
type AbstractBatch []Abstract

// RunForErrors implements AbstractResult interface.
func (ab AbstractBatch) RunForErrors(f func(jsonErr *Error)) {
for _, a := range ab {
if a.Error != nil {
f(a.Error)
}
}
}

// Notification is a type used to represent wire format of events, they're
// special in that they look like requests but they don't have IDs and their
// "method" is actually an event name.
Expand Down
57 changes: 57 additions & 0 deletions pkg/rpc/server/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package server

import (
"net/http"

"github.com/nspcc-dev/neo-go/pkg/rpc/response"
)

// abstractResult is an interface which represents either single JSON-RPC 2.0 response
// or batch JSON-RPC 2.0 response.
type abstractResult interface {
RunForErrors(f func(jsonErr *response.Error))
}

// abstract represents abstract JSON-RPC 2.0 response. It is used as a server-side response
// representation.
type abstract struct {
response.Header
Error *response.Error `json:"error,omitempty"`
Result interface{} `json:"result,omitempty"`
}

// RunForErrors implements abstractResult interface.
func (a abstract) RunForErrors(f func(jsonErr *response.Error)) {
if a.Error != nil {
f(a.Error)
}
}

// abstractBatch represents abstract JSON-RPC 2.0 batch-response.
type abstractBatch []abstract

// RunForErrors implements abstractResult interface.
func (ab abstractBatch) RunForErrors(f func(jsonErr *response.Error)) {
for _, a := range ab {
if a.Error != nil {
f(a.Error)
}
}
}

func getHTTPCodeForError(respErr *response.Error) int {
var httpCode int
switch respErr.Code {
case response.BadRequestCode:
httpCode = http.StatusBadRequest
case response.InvalidRequestCode, response.RPCErrorCode, response.InvalidParamsCode:
httpCode = http.StatusUnprocessableEntity
case response.MethodNotFoundCode:
httpCode = http.StatusMethodNotAllowed
case response.InternalServerErrorCode:
httpCode = http.StatusInternalServerError
default:
httpCode = http.StatusUnprocessableEntity
}
return httpCode
}
Loading