diff --git a/rpc/lib/server/handlers.go b/rpc/lib/server/handlers.go index a4df4b840..070072d8f 100644 --- a/rpc/lib/server/handlers.go +++ b/rpc/lib/server/handlers.go @@ -110,11 +110,11 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han var request types.RPCRequest err := json.Unmarshal(b, &request) if err != nil { - WriteRPCResponseHTTP(w, types.RPCParseError("")) + WriteRPCResponseHTTP(w, types.RPCParseError("", errors.Wrap(err, "Error unmarshalling request"))) return } if len(r.URL.Path) > 1 { - WriteRPCResponseHTTP(w, types.RPCInvalidRequestError(request.ID)) + WriteRPCResponseHTTP(w, types.RPCInvalidRequestError(request.ID, errors.Errorf("Path %s is invalid", r.URL.Path))) return } rpcFunc := funcMap[request.Method] @@ -123,19 +123,19 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han return } if rpcFunc.ws { - WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID)) + WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID, errors.New("Trying to use Websocket method in non-ws context"))) return } args, err := jsonParamsToArgsRPC(rpcFunc, request.Params) if err != nil { - WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID)) + WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID, errors.Wrap(err, "Error converting json params to arguments"))) return } returns := rpcFunc.f.Call(args) logger.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns) result, err := unreflectResult(returns) if err != nil { - WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID)) + WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID, err)) return } WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(request.ID, result)) @@ -229,7 +229,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit // Exception for websocket endpoints if rpcFunc.ws { return func(w http.ResponseWriter, r *http.Request) { - WriteRPCResponseHTTP(w, types.RPCInternalError("")) + WriteRPCResponseHTTP(w, types.RPCInternalError("", errors.New("Trying to use Websocket method in non-ws context"))) } } // All other endpoints @@ -237,14 +237,14 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit logger.Debug("HTTP HANDLER", "req", r) args, err := httpParamsToArgs(rpcFunc, r) if err != nil { - WriteRPCResponseHTTP(w, types.RPCInvalidParamsError("")) + WriteRPCResponseHTTP(w, types.RPCInvalidParamsError("", errors.Wrap(err, "Error converting http params to arguments"))) return } returns := rpcFunc.f.Call(args) logger.Info("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns) result, err := unreflectResult(returns) if err != nil { - WriteRPCResponseHTTP(w, types.RPCInternalError("")) + WriteRPCResponseHTTP(w, types.RPCInternalError("", err)) return } WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse("", result)) @@ -509,7 +509,7 @@ func (wsc *wsConnection) readRoutine() { var request types.RPCRequest err = json.Unmarshal(in, &request) if err != nil { - wsc.WriteRPCResponse(types.RPCParseError("")) + wsc.WriteRPCResponse(types.RPCParseError("", errors.Wrap(err, "Error unmarshaling request"))) continue } @@ -528,7 +528,7 @@ func (wsc *wsConnection) readRoutine() { args, err = jsonParamsToArgsRPC(rpcFunc, request.Params) } if err != nil { - wsc.WriteRPCResponse(types.RPCInternalError(request.ID)) + wsc.WriteRPCResponse(types.RPCInternalError(request.ID, errors.Wrap(err, "Error converting json params to arguments"))) continue } returns := rpcFunc.f.Call(args) @@ -538,7 +538,7 @@ func (wsc *wsConnection) readRoutine() { result, err := unreflectResult(returns) if err != nil { - wsc.WriteRPCResponse(types.RPCInternalError(request.ID)) + wsc.WriteRPCResponse(types.RPCInternalError(request.ID, err)) continue } else { wsc.WriteRPCResponse(types.NewRPCSuccessResponse(request.ID, result)) diff --git a/rpc/lib/server/http_server.go b/rpc/lib/server/http_server.go index 2d6f5f1ba..7623337db 100644 --- a/rpc/lib/server/http_server.go +++ b/rpc/lib/server/http_server.go @@ -12,6 +12,7 @@ import ( "time" "github.com/pkg/errors" + types "github.com/tendermint/tendermint/rpc/lib/types" "github.com/tendermint/tmlibs/log" ) @@ -99,7 +100,7 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler // For the rest, logger.Error("Panic in RPC HTTP handler", "err", e, "stack", string(debug.Stack())) rww.WriteHeader(http.StatusInternalServerError) - WriteRPCResponseHTTP(rww, types.RPCInternalError("")) + WriteRPCResponseHTTP(rww, types.RPCInternalError("", e.(error))) } } diff --git a/rpc/lib/types/types.go b/rpc/lib/types/types.go index 528255a83..b649d1b94 100644 --- a/rpc/lib/types/types.go +++ b/rpc/lib/types/types.go @@ -5,13 +5,13 @@ import ( "fmt" "strings" + "github.com/pkg/errors" + events "github.com/tendermint/tmlibs/events" ) -type RpcError struct { - Code int `json:"code"` - Message string `json:"message"` -} +//---------------------------------------- +// REQUEST type RPCRequest struct { JSONRPC string `json:"jsonrpc"` @@ -52,6 +52,13 @@ func ArrayToRequest(id string, method string, params []interface{}) (RPCRequest, } //---------------------------------------- +// RESPONSE + +type RpcError struct { + Code int `json:"code"` + Message string `json:"message"` + Data string `json:"data,omitempty"` +} type RPCResponse struct { JSONRPC string `json:"jsonrpc"` @@ -67,7 +74,7 @@ func NewRPCSuccessResponse(id string, res interface{}) RPCResponse { var js []byte js, err := json.Marshal(res) if err != nil { - return RPCInternalError(id) + return RPCInternalError(id, errors.Wrap(err, "Error marshalling response")) } rawMsg := json.RawMessage(js) raw = &rawMsg @@ -76,11 +83,11 @@ func NewRPCSuccessResponse(id string, res interface{}) RPCResponse { return RPCResponse{JSONRPC: "2.0", ID: id, Result: raw} } -func NewRPCErrorResponse(id string, code int, msg string) RPCResponse { +func NewRPCErrorResponse(id string, code int, msg string, data string) RPCResponse { return RPCResponse{ JSONRPC: "2.0", ID: id, - Error: &RpcError{Code: code, Message: msg}, + Error: &RpcError{Code: code, Message: msg, Data: data}, } } @@ -92,28 +99,28 @@ func (resp RPCResponse) String() string { } } -func RPCParseError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32700, "Parse error. Invalid JSON") +func RPCParseError(id string, err error) RPCResponse { + return NewRPCErrorResponse(id, -32700, "Parse error. Invalid JSON", err.Error()) } -func RPCInvalidRequestError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32600, "Invalid Request") +func RPCInvalidRequestError(id string, err error) RPCResponse { + return NewRPCErrorResponse(id, -32600, "Invalid Request", err.Error()) } func RPCMethodNotFoundError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32601, "Method not found") + return NewRPCErrorResponse(id, -32601, "Method not found", "") } -func RPCInvalidParamsError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32602, "Invalid params") +func RPCInvalidParamsError(id string, err error) RPCResponse { + return NewRPCErrorResponse(id, -32602, "Invalid params", err.Error()) } -func RPCInternalError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32603, "Internal error") +func RPCInternalError(id string, err error) RPCResponse { + return NewRPCErrorResponse(id, -32603, "Internal error", err.Error()) } -func RPCServerError(id string) RPCResponse { - return NewRPCErrorResponse(id, -32000, "Server error") +func RPCServerError(id string, err error) RPCResponse { + return NewRPCErrorResponse(id, -32000, "Server error", err.Error()) } //---------------------------------------- @@ -133,7 +140,7 @@ type WSRPCContext struct { } //---------------------------------------- -// sockets +// SOCKETS // // Determine if its a unix or tcp socket. // If tcp, must specify the port; `0.0.0.0` will return incorrectly as "unix" since there's no port diff --git a/rpc/lib/types/types_test.go b/rpc/lib/types/types_test.go index 14688ecee..bab42124a 100644 --- a/rpc/lib/types/types_test.go +++ b/rpc/lib/types/types_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -19,14 +20,13 @@ func TestResponses(t *testing.T) { s := `{"jsonrpc":"2.0","id":"1","result":{"Value":"hello"}}` assert.Equal(string(s), string(b)) - d := RPCParseError("1") + d := RPCParseError("1", errors.New("Hello world")) e, _ := json.Marshal(d) - f := `{"jsonrpc":"2.0","id":"1","error":{"code":-32700,"message":"Parse error. Invalid JSON"}}` + f := `{"jsonrpc":"2.0","id":"1","error":{"code":-32700,"message":"Parse error. Invalid JSON","data":"Hello world"}}` assert.Equal(string(f), string(e)) g := RPCMethodNotFoundError("2") h, _ := json.Marshal(g) i := `{"jsonrpc":"2.0","id":"2","error":{"code":-32601,"message":"Method not found"}}` assert.Equal(string(h), string(i)) - }