From 5803923f68d217177c807bd88a1640d4a2118324 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 7 Jun 2022 12:27:58 +0300 Subject: [PATCH 1/5] rpc: remove Cause field from RPC error We can use Data field for the same purposes. --- pkg/rpc/response/errors.go | 43 ++++---- pkg/rpc/server/server.go | 202 ++++++++++++++++++------------------- 2 files changed, 119 insertions(+), 126 deletions(-) diff --git a/pkg/rpc/response/errors.go b/pkg/rpc/response/errors.go index 2a5951e72..53aa1d683 100644 --- a/pkg/rpc/response/errors.go +++ b/pkg/rpc/response/errors.go @@ -1,7 +1,6 @@ package response import ( - "errors" "fmt" "net/http" ) @@ -12,7 +11,6 @@ type ( Error struct { Code int64 `json:"code"` HTTPCode int `json:"-"` - Cause error `json:"-"` Message string `json:"message"` Data string `json:"data,omitempty"` } @@ -23,7 +21,7 @@ const InternalServerErrorCode = -32603 var ( // ErrInvalidParams represents a generic 'invalid parameters' error. - ErrInvalidParams = NewInvalidParamsError("", errors.New("invalid params")) + ErrInvalidParams = NewInvalidParamsError("invalid params") // 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. @@ -40,11 +38,10 @@ var ( // 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 { +func NewError(code int64, httpCode int, message string, data string) *Error { return &Error{ Code: code, HTTPCode: httpCode, - Cause: cause, Message: message, Data: data, } @@ -52,56 +49,56 @@ func NewError(code int64, httpCode int, message string, data string, cause error // 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(-32700, http.StatusBadRequest, "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(-32600, http.StatusUnprocessableEntity, "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(-32601, http.StatusMethodNotAllowed, "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(-32602, http.StatusUnprocessableEntity, "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, http.StatusInternalServerError, "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(-100, http.StatusUnprocessableEntity, 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, http.StatusUnprocessableEntity, message, "") } // 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) +func WrapErrorWithData(e *Error, data string) *Error { + return NewError(e.Code, e.HTTPCode, e.Message, data) } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 5c500d38f..035d06dd9 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -159,7 +159,7 @@ var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (inter } var invalidBlockHeightError = func(index int, height int) *response.Error { - return response.NewRPCError(fmt.Sprintf("Param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height), "", nil) + return response.NewRPCError("Invalid block height", fmt.Sprintf("param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height)) } // upgrader is a no-op websocket.Upgrader that reuses HTTP server buffers and @@ -301,7 +301,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.writeHTTPErrorResponse( request.NewIn(), w, - response.NewInternalServerError("websocket users limit reached", fmt.Errorf("%d subscribers are allowed at max", maxSubscribers)), + response.NewInternalServerError("websocket users limit reached"), ) return } @@ -325,16 +325,14 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.writeHTTPErrorResponse( request.NewIn(), w, - response.NewInvalidParamsError( - fmt.Sprintf("Invalid method '%s', please retry with 'POST'", httpRequest.Method), errors.New("unsupported HTTP request method"), - ), + response.NewInvalidParamsError(fmt.Sprintf("invalid method '%s', please retry with 'POST'", httpRequest.Method)), ) return } err := req.DecodeData(httpRequest.Body) if err != nil { - s.writeHTTPErrorResponse(request.NewIn(), w, response.NewParseError("Problem parsing JSON-RPC request body", err)) + s.writeHTTPErrorResponse(request.NewIn(), w, response.NewParseError(err.Error())) return } @@ -359,7 +357,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract { var res interface{} var resErr *response.Error if req.JSONRPC != request.JSONRPCVersion { - return s.packResponse(req, nil, response.NewInvalidParamsError("Problem parsing JSON", fmt.Errorf("invalid version, expected 2.0 got: '%s'", req.JSONRPC))) + return s.packResponse(req, nil, response.NewInvalidParamsError(fmt.Sprintf("problem parsing JSON: invalid version, expected 2.0 got '%s'", req.JSONRPC))) } reqParams := request.Params(req.RawParams) @@ -370,7 +368,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract { incCounter(req.Method) - resErr = response.NewMethodNotFoundError(fmt.Sprintf("Method %q not supported", req.Method), errors.New("unsupported method call")) + resErr = response.NewMethodNotFoundError(fmt.Sprintf("method %q not supported", req.Method)) handler, ok := rpcHandlers[req.Method] if ok { res, resErr = handler(s, reqParams) @@ -513,7 +511,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro block, err := s.chain.GetBlock(hash) if err != nil { - return nil, response.NewRPCError(fmt.Sprintf("Problem locating block with hash: %s", hash), err.Error(), err) + return nil, response.NewRPCError("Failed to get block", err.Error()) } if v, _ := reqParams.Value(1).GetBoolean(); v { @@ -536,7 +534,7 @@ func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response. func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { port, err := s.coreServer.Port() if err != nil { - return nil, response.NewInternalServerError("Cannot fetch tcp port", err) + return nil, response.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err)) } cfg := s.chain.GetConfig() @@ -605,15 +603,15 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re } byteTx, err := reqParams[0].GetBytesBase64() if err != nil { - return 0, response.WrapErrorWithData(response.ErrInvalidParams, err) + return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } tx, err := transaction.NewTransactionFromBytes(byteTx) if err != nil { - return 0, response.WrapErrorWithData(response.ErrInvalidParams, err) + return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } hashablePart, err := tx.EncodeHashableFields() if err != nil { - return 0, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("failed to compute tx size: %w", err)) + return 0, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Sprintf("failed to compute tx size: %s", err)) } size := len(hashablePart) + io.GetVarSize(len(tx.Signers)) var ( @@ -632,7 +630,7 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re if verificationScript == nil { // then it still might be a contract-based verification gasConsumed, err := s.chain.VerifyWitness(signer.Account, tx, &tx.Scripts[i], int64(s.config.MaxGasInvoke)) if err != nil { - return 0, response.NewRPCError(fmt.Sprintf("contract verification for signer #%d failed", i), err.Error(), err) + return 0, response.NewRPCError("Invalid signature", fmt.Sprintf("contract verification for signer #%d failed: %s", i, err)) } netFee += gasConsumed size += io.GetVarSize([]byte{}) + // verification script is empty (contract-based witness) @@ -673,7 +671,7 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *resp appExecResults, err := s.chain.GetAppExecResults(hash, trigger.All) if err != nil { - return nil, response.NewRPCError("Unknown transaction or block", "", err) + return nil, response.NewRPCError("Unknown transaction or block", fmt.Sprintf("failed to locate application log: %s", err)) } return result.NewApplicationLog(hash, appExecResults, trig), nil } @@ -703,7 +701,7 @@ func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.Err } lastUpdated, err := s.chain.GetTokenLastUpdated(u) if err != nil { - return nil, response.NewRPCError("Failed to get NEP-11 last updated block", err.Error(), err) + return nil, response.NewRPCError("Failed to get NEP-11 last updated block", err.Error()) } var count int stateSyncPoint := lastUpdated[math.MinInt32] @@ -726,7 +724,7 @@ contract_loop: if !ok { cfg := s.chain.GetConfig() if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks { - return nil, response.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token", cs.Hash.StringLE()), errors.New("internal database inconsistency")) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE())) } lub = stateSyncPoint } @@ -788,7 +786,7 @@ func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.E } props, err := s.invokeNEP11Properties(asset, token, nil) if err != nil { - return nil, response.NewRPCError("failed to get NEP-11 properties", err.Error(), err) + return nil, response.NewRPCError("Failed to get NEP-11 properties", err.Error()) } res := make(map[string]interface{}) for _, kv := range props { @@ -825,7 +823,7 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err } lastUpdated, err := s.chain.GetTokenLastUpdated(u) if err != nil { - return nil, response.NewRPCError("Failed to get NEP-17 last updated block", err.Error(), err) + return nil, response.NewRPCError("Failed to get NEP-17 last updated block", err.Error()) } stateSyncPoint := lastUpdated[math.MinInt32] bw := io.NewBufBinWriter() @@ -845,7 +843,7 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err if !ok { cfg := s.chain.GetConfig() if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks { - return nil, response.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token", cs.Hash.StringLE()), errors.New("internal database inconsistency")) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE())) } lub = stateSyncPoint } @@ -977,7 +975,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{} start, end, limit, page, err := getTimestampsAndLimit(ps, 1) if err != nil { - return nil, response.NewInvalidParamsError(err.Error(), err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("malformed timestamps/limit: %s", err)) } bs := &tokenTransfers{ @@ -1068,7 +1066,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{} }) } if err != nil { - return nil, response.NewInternalServerError(fmt.Sprintf("invalid transfer log: %v", err), err) + return nil, response.NewInternalServerError(fmt.Sprintf("invalid transfer log: %s", err)) } return bs, nil } @@ -1103,7 +1101,7 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err return 0, response.ErrInvalidParams } if err := checkInt32(id); err != nil { - return 0, response.WrapErrorWithData(response.ErrInvalidParams, err) + return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } result = int32(id) } @@ -1130,14 +1128,14 @@ func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160 } id, err := strconv.Atoi(nameOrHashOrIndex) if err != nil { - return result, response.NewRPCError("Unknown contract", "", err) + return result, response.NewRPCError("Invalid contract identifier (name/hash/index is expected)", err.Error()) } if err := checkInt32(id); err != nil { - return result, response.WrapErrorWithData(response.ErrInvalidParams, err) + return result, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } result, err = s.chain.GetContractScriptHash(int32(id)) if err != nil { - return result, response.NewRPCError("Unknown contract", "", err) + return result, response.NewRPCError("Unknown contract", "") } return result, nil } @@ -1153,7 +1151,7 @@ var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enable func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { - return nil, response.NewInvalidRequestError("'getproof' is not supported", errKeepOnlyLatestState) + return nil, response.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) } root, err := ps.Value(0).GetUint256() if err != nil { @@ -1174,7 +1172,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { skey := makeStorageKey(cs.ID, key) proof, err := s.chain.GetStateModule().GetStateProof(root, skey) if err != nil { - return nil, response.NewInternalServerError("failed to get proof", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get proof: %s", err)) } return &result.ProofWithKey{ Key: skey, @@ -1184,7 +1182,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { - return nil, response.NewInvalidRequestError("'verifyproof' is not supported", errKeepOnlyLatestState) + return nil, response.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) } root, err := ps.Value(0).GetUint256() if err != nil { @@ -1209,24 +1207,24 @@ func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid stateroot")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") } if s.chain.GetConfig().KeepOnlyLatestState { curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight()) if err != nil { - return nil, response.NewInternalServerError("failed to get current stateroot", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) } if !curr.Root.Equals(root) { - return nil, response.NewInvalidRequestError("'getstate' is not supported for old states", errKeepOnlyLatestState) + return nil, response.NewInvalidRequestError(fmt.Sprintf("'getstate' is not supported for old states: %s", errKeepOnlyLatestState)) } } csHash, err := ps.Value(1).GetUint160FromHex() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid contract hash")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid contract hash") } key, err := ps.Value(2).GetBytesBase64() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid key")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid key") } cs, respErr := s.getHistoricalContractState(root, csHash) if respErr != nil { @@ -1235,7 +1233,7 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { sKey := makeStorageKey(cs.ID, key) res, err := s.chain.GetStateModule().GetState(root, sKey) if err != nil { - return nil, response.NewRPCError("failed to get historical item state", err.Error(), err) + return nil, response.NewRPCError("Failed to get historical item state", err.Error()) } return res, nil } @@ -1243,24 +1241,24 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid stateroot")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") } if s.chain.GetConfig().KeepOnlyLatestState { curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight()) if err != nil { - return nil, response.NewInternalServerError("failed to get current stateroot", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) } if !curr.Root.Equals(root) { - return nil, response.NewInvalidRequestError("'findstates' is not supported for old states", errKeepOnlyLatestState) + return nil, response.NewInvalidRequestError(fmt.Sprintf("'findstates' is not supported for old states: %s", errKeepOnlyLatestState)) } } csHash, err := ps.Value(1).GetUint160FromHex() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid contract hash: %w", err)) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Sprintf("invalid contract hash: %s", err)) } prefix, err := ps.Value(2).GetBytesBase64() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid prefix: %w", err)) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Sprintf("invalid prefix: %s", err)) } var ( key []byte @@ -1269,11 +1267,11 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(ps) > 3 { key, err = ps.Value(3).GetBytesBase64() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid key: %w", err)) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Sprintf("invalid key: %s", err)) } if len(key) > 0 { if !bytes.HasPrefix(key, prefix) { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("key doesn't match prefix")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "key doesn't match prefix") } key = key[len(prefix):] } else { @@ -1284,7 +1282,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(ps) > 4 { count, err = ps.Value(4).GetInt() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid count: %w", err)) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Sprintf("invalid count: %s", err)) } if count > s.config.MaxFindResultItems { count = s.config.MaxFindResultItems @@ -1297,7 +1295,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { pKey := makeStorageKey(cs.ID, prefix) kvs, err := s.chain.GetStateModule().FindStates(root, pKey, key, count+1) // +1 to define result truncation if err != nil { - return nil, response.NewInternalServerError("failed to find historical items", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to find historical items: %s", err)) } res := result.FindStates{} if len(kvs) == count+1 { @@ -1307,7 +1305,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(kvs) > 0 { proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[0].Key) if err != nil { - return nil, response.NewInternalServerError("failed to get first proof", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get first proof: %s", err)) } res.FirstProof = &result.ProofWithKey{ Key: kvs[0].Key, @@ -1317,7 +1315,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(kvs) > 1 { proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[len(kvs)-1].Key) if err != nil { - return nil, response.NewInternalServerError("failed to get last proof", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to get last proof: %s", err)) } res.LastProof = &result.ProofWithKey{ Key: kvs[len(kvs)-1].Key, @@ -1338,12 +1336,12 @@ func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint1 csKey := makeStorageKey(native.ManagementContractID, native.MakeContractKey(csHash)) csBytes, err := s.chain.GetStateModule().GetState(root, csKey) if err != nil { - return nil, response.NewRPCError("failed to get historical contract state", err.Error(), err) + return nil, response.NewRPCError("Failed to get historical contract state", err.Error()) } contract := new(state.Contract) err = stackitem.DeserializeConvertible(csBytes, contract) if err != nil { - return nil, response.NewInternalServerError("failed to deserialize historical contract state", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to deserialize historical contract state: %s", err)) } return contract, nil } @@ -1363,14 +1361,14 @@ func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) { p := ps.Value(0) if p == nil { - return nil, response.NewInvalidParamsError("Invalid parameter.", errors.New("missing stateroot identifier ")) + return nil, response.NewInvalidParamsError("missing stateroot identifier") } var rt *state.MPTRoot var h util.Uint256 height, err := p.GetIntStrict() if err == nil { if err := checkUint32(height); err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, err) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } rt, err = s.chain.GetStateModule().GetStateRoot(uint32(height)) } else if h, err = p.GetUint256(); err == nil { @@ -1381,7 +1379,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) } } if err != nil { - return nil, response.NewRPCError("Unknown state root.", "", err) + return nil, response.NewRPCError("Unknown state root", "") } return rt, nil } @@ -1415,8 +1413,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp } tx, height, err := s.chain.GetTransaction(txHash) if err != nil { - err = fmt.Errorf("invalid transaction %s: %w", txHash, err) - return nil, response.NewRPCError("Unknown transaction", err.Error(), err) + return nil, response.NewRPCError("Unknown transaction", "") } if v, _ := reqParams.Value(1).GetBoolean(); v { if height == math.MaxUint32 { @@ -1425,14 +1422,14 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp _header := s.chain.GetHeaderHash(int(height)) header, err := s.chain.GetHeader(_header) if err != nil { - return nil, response.NewRPCError("Failed to get header for the transaction", err.Error(), err) + return nil, response.NewRPCError("Failed to get header for the transaction", err.Error()) } aers, err := s.chain.GetAppExecResults(txHash, trigger.Application) if err != nil { - return nil, response.NewRPCError("Failed to get application log for the transaction", err.Error(), err) + return nil, response.NewRPCError("Failed to get application log for the transaction", err.Error()) } if len(aers) == 0 { - return nil, response.NewRPCError("Application log for the transaction is empty", "", errors.New("inconsistent application log")) + return nil, response.NewRPCError("Inconsistent application log", "application log for the transaction is empty") } return result.NewTransactionOutputRaw(tx, header, &aers[0], s.chain), nil } @@ -1447,7 +1444,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response _, height, err := s.chain.GetTransaction(h) if err != nil || height == math.MaxUint32 { - return nil, response.NewRPCError("Unknown transaction", "", errors.New("transaction not found")) + return nil, response.NewRPCError("Unknown transaction", "") } return height, nil @@ -1462,7 +1459,7 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, *respo } cs := s.chain.GetContractState(scriptHash) if cs == nil { - return nil, response.NewRPCError("Unknown contract", "", errors.New("contract not found")) + return nil, response.NewRPCError("Unknown contract", "") } return cs, nil } @@ -1475,13 +1472,13 @@ func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.Er func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { - return 0, response.NewRPCError("Invalid height", "", errors.New("invalid block identifier")) + return 0, response.NewRPCError("Invalid height", "invalid block identifier") } headerHash := s.chain.GetHeaderHash(num) block, errBlock := s.chain.GetBlock(headerHash) if errBlock != nil { - return 0, response.NewRPCError(errBlock.Error(), "", errors.New("unknown block")) + return 0, response.NewRPCError("Unknown block", "") } var blockSysFee int64 @@ -1503,7 +1500,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons verbose, _ := reqParams.Value(1).GetBoolean() h, err := s.chain.GetHeader(hash) if err != nil { - return nil, response.NewRPCError("unknown block", "", errors.New("unknown header")) + return nil, response.NewRPCError("Unknown header", "") } if verbose { @@ -1513,7 +1510,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons buf := io.NewBufBinWriter() h.EncodeBinary(buf.BinWriter) if buf.Err != nil { - return nil, response.NewInternalServerError("encoding error", buf.Err) + return nil, response.NewInternalServerError(fmt.Sprintf("encoding error: %s", buf.Err)) } return buf.Bytes(), nil } @@ -1533,7 +1530,7 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro } gas, err := s.chain.CalculateClaimable(u, s.chain.BlockHeight()+1) // +1 as in C#, for the next block. if err != nil { - return nil, response.NewRPCError("can't calculate claimable", err.Error(), err) + return nil, response.NewRPCError("Can't calculate claimable", err.Error()) } return result.UnclaimedGas{ Address: u, @@ -1547,11 +1544,11 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons validators, err := s.chain.GetNextBlockValidators() if err != nil { - return nil, response.NewRPCError("can't get next block validators", "", err) + return nil, response.NewRPCError("Can't get next block validators", err.Error()) } enrollments, err := s.chain.GetEnrollments() if err != nil { - return nil, response.NewRPCError("can't get enrollments", "", err) + return nil, response.NewRPCError("Can't get enrollments", err.Error()) } var res = make([]result.Validator, 0) for _, v := range enrollments { @@ -1568,7 +1565,7 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { keys, err := s.chain.GetCommittee() if err != nil { - return nil, response.NewInternalServerError("can't get committee members", err) + return nil, response.NewInternalServerError(fmt.Sprintf("can't get committee members: %s", err)) } return keys, nil } @@ -1634,7 +1631,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction } script, err := request.CreateFunctionInvocationScript(scriptHash, method, params) if err != nil { - return nil, false, response.NewInternalServerError("can't create invocation script", err) + return nil, false, response.NewInternalServerError(fmt.Sprintf("can't create invocation script: %s", err)) } tx.Script = script return tx, verbose, nil @@ -1675,7 +1672,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T if len(reqParams) > 1 { signers, witnesses, err := reqParams[1].GetSignersWithWitnesses() if err != nil { - return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err) + return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } tx.Signers = signers tx.Scripts = witnesses @@ -1684,7 +1681,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T if len(reqParams) > 2 { verbose, err = reqParams[2].GetBoolean() if err != nil { - return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err) + return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } } if len(tx.Signers) == 0 { @@ -1729,12 +1726,12 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U if len(reqParams) > 1 { args, err := reqParams[1].GetArray() // second `invokecontractverify` parameter is an array of arguments for `verify` method if err != nil { - return util.Uint160{}, nil, nil, response.WrapErrorWithData(response.ErrInvalidParams, err) + return util.Uint160{}, nil, nil, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } if len(args) > 0 { err := request.ExpandArrayIntoScript(bw.BinWriter, args) if err != nil { - return util.Uint160{}, nil, nil, response.NewInternalServerError("can't create witness invocation script", err) + return util.Uint160{}, nil, nil, response.NewInternalServerError(fmt.Sprintf("can't create witness invocation script: %s", err)) } } } @@ -1761,7 +1758,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U // handling consistency. func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { - return nil, response.NewInvalidRequestError("only latest state is supported", errKeepOnlyLatestState) + return nil, response.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) } if len(reqParams) < 1 { return nil, response.ErrInvalidParams @@ -1770,13 +1767,13 @@ func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *res if respErr != nil { hash, err := reqParams.Value(0).GetUint256() if err != nil { - return nil, response.NewInvalidParamsError("invalid block hash or index or stateroot hash", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("invalid block hash or index or stateroot hash: %s", err)) } b, err := s.chain.GetBlock(hash) if err != nil { stateH, err := s.chain.GetStateModule().GetLatestStateHeight(hash) if err != nil { - return nil, response.NewInvalidParamsError(fmt.Sprintf("unknown block or stateroot: %s", err), err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("unknown block or stateroot: %s", err)) } height = int(stateH) } else { @@ -1785,7 +1782,7 @@ func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *res } b, err := s.getFakeNextBlock(uint32(height)) if err != nil { - return nil, response.NewInternalServerError(fmt.Sprintf("can't create fake block for height %d: %s", height, err.Error()), err) + return nil, response.NewInternalServerError(fmt.Sprintf("can't create fake block for height %d: %s", height, err)) } return b, nil } @@ -1817,13 +1814,13 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash if b == nil { b, err = s.getFakeNextBlock(s.chain.BlockHeight() + 1) if err != nil { - return nil, response.NewInternalServerError("can't create fake block", err) + return nil, response.NewInternalServerError(fmt.Sprintf("can't create fake block: %s", err)) } ic = s.chain.GetTestVM(t, tx, b) } else { ic, err = s.chain.GetTestHistoricVM(t, tx, b) if err != nil { - return nil, response.NewInternalServerError("failed to create historic VM", err) + return nil, response.NewInternalServerError(fmt.Sprintf("failed to create historic VM: %s", err)) } } if verbose { @@ -1840,7 +1837,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash err = s.chain.InitVerificationContext(ic, contractScriptHash, &transaction.Witness{InvocationScript: script, VerificationScript: []byte{}}) if err != nil { - return nil, response.NewInternalServerError(fmt.Sprintf("can't prepare verification VM: %s", err.Error()), err) + return nil, response.NewInternalServerError(fmt.Sprintf("can't prepare verification VM: %s", err)) } } else { ic.VM.LoadScriptWithFlags(script, callflag.All) @@ -1857,21 +1854,21 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) { blockBytes, err := reqParams.Value(0).GetBytesBase64() if err != nil { - return nil, response.NewInvalidParamsError("missing parameter or not base64", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err)) } b := block.New(s.stateRootEnabled) r := io.NewBinReaderFromBuf(blockBytes) b.DecodeBinary(r) if r.Err != nil { - return nil, response.NewInvalidParamsError("can't decode block", r.Err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("can't decode block: %s", r.Err)) } err = s.chain.AddBlock(b) if err != nil { switch { case errors.Is(err, core.ErrInvalidBlockIndex) || errors.Is(err, core.ErrAlreadyExists): - return nil, response.WrapErrorWithData(response.ErrAlreadyExists, err) + return nil, response.WrapErrorWithData(response.ErrAlreadyExists, err.Error()) default: - return nil, response.WrapErrorWithData(response.ErrValidationFailed, err) + return nil, response.WrapErrorWithData(response.ErrValidationFailed, err.Error()) } } return &result.RelayResult{ @@ -1882,16 +1879,16 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.E // submitNotaryRequest broadcasts P2PNotaryRequest over the NEO network. func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.Error) { if !s.chain.P2PSigExtensionsEnabled() { - return nil, response.NewRPCError("P2PNotaryRequest was received, but P2PSignatureExtensions are disabled", "", errors.New("P2PSignatureExtensions are disabled")) + return nil, response.NewRPCError("P2PSignatureExtensions are disabled", "") } bytePayload, err := ps.Value(0).GetBytesBase64() if err != nil { - return nil, response.NewInvalidParamsError("not base64", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("not a base64: %s", err)) } r, err := payload.NewP2PNotaryRequestFromBytes(bytePayload) if err != nil { - return nil, response.NewInvalidParamsError("can't decode notary payload", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("can't decode notary payload: %s", err)) } return getRelayResult(s.coreServer.RelayP2PNotaryRequest(r), r.FallbackTransaction.Hash()) } @@ -1904,19 +1901,19 @@ func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Error) Hash: hash, }, nil case errors.Is(err, core.ErrAlreadyExists): - return nil, response.WrapErrorWithData(response.ErrAlreadyExists, err) + return nil, response.WrapErrorWithData(response.ErrAlreadyExists, err.Error()) case errors.Is(err, core.ErrOOM): - return nil, response.WrapErrorWithData(response.ErrOutOfMemory, err) + return nil, response.WrapErrorWithData(response.ErrOutOfMemory, err.Error()) case errors.Is(err, core.ErrPolicy): - return nil, response.WrapErrorWithData(response.ErrPolicyFail, err) + return nil, response.WrapErrorWithData(response.ErrPolicyFail, err.Error()) default: - return nil, response.WrapErrorWithData(response.ErrValidationFailed, err) + return nil, response.WrapErrorWithData(response.ErrValidationFailed, err.Error()) } } func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.Error) { if s.oracle == nil { - return nil, response.NewRPCError("oracle is not enabled", "", errors.New("oracle service is disabled")) + return nil, response.NewRPCError("Oracle is not enabled", "") } var pub *keys.PublicKey pubBytes, err := ps.Value(0).GetBytesBase64() @@ -1924,23 +1921,23 @@ func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response pub, err = keys.NewPublicKeyFromBytes(pubBytes, elliptic.P256()) } if err != nil { - return nil, response.NewInvalidParamsError("public key is missing", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("public key is missing: %s", err)) } reqID, err := ps.Value(1).GetInt() if err != nil { - return nil, response.NewInvalidParamsError("request ID is missing", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("request ID is missing: %s", err)) } txSig, err := ps.Value(2).GetBytesBase64() if err != nil { - return nil, response.NewInvalidParamsError("tx signature is missing", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("tx signature is missing: %s", err)) } msgSig, err := ps.Value(3).GetBytesBase64() if err != nil { - return nil, response.NewInvalidParamsError("msg signature is missing", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("msg signature is missing: %s", err)) } data := broadcaster.GetMessage(pubBytes, uint64(reqID), txSig) if !pub.Verify(msgSig, hash.Sha256(data).BytesBE()) { - return nil, response.NewRPCError("Invalid sign", "", errors.New("invalid request signature")) + return nil, response.NewRPCError("Invalid request signature", "") } s.oracle.AddResponse(pub, uint64(reqID), txSig) return json.RawMessage([]byte("{}")), nil @@ -1948,15 +1945,15 @@ func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) { if len(reqParams) < 1 { - return nil, response.NewInvalidParamsError("not enough parameters", errors.New("invalid parameters")) + return nil, response.NewInvalidParamsError("not enough parameters") } byteTx, err := reqParams[0].GetBytesBase64() if err != nil { - return nil, response.NewInvalidParamsError("not base64", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("not a base64: %s", err)) } tx, err := transaction.NewTransactionFromBytes(byteTx) if err != nil { - return nil, response.NewInvalidParamsError("can't decode transaction", err) + return nil, response.NewInvalidParamsError(fmt.Sprintf("can't decode transaction: %s", err)) } return getRelayResult(s.coreServer.RelayTxn(tx), tx.Hash()) } @@ -1972,7 +1969,7 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface return nil, response.ErrInvalidParams } if event == response.NotaryRequestEventID && !s.chain.P2PSigExtensionsEnabled() { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("P2PSigExtensions are disabled")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, "P2PSigExtensions are disabled") } // Optional filter. var filter interface{} @@ -2011,8 +2008,7 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface defer s.subsLock.Unlock() select { case <-s.shutdown: - err = errors.New("server is shutting down") - return nil, response.NewInternalServerError(err.Error(), err) + return nil, response.NewInternalServerError("server is shutting down") default: } var id int @@ -2022,7 +2018,7 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface } } if id == len(sub.feeds) { - return nil, response.NewInternalServerError("maximum number of subscriptions is reached", fmt.Errorf("%d subscriptions are allowed at max", len(sub.feeds))) + return nil, response.NewInternalServerError("maximum number of subscriptions is reached") } sub.feeds[id].event = event sub.feeds[id].filter = filter @@ -2266,7 +2262,7 @@ func (s *Server) packResponse(r *request.In, result interface{}, respErr *respon // logRequestError is a request error logger. func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { logFields := []zap.Field{ - zap.Error(jsonErr.Cause), + zap.String("cause", jsonErr.Data), } if r.In != nil { From 0687924e872b12e4df764b1120d40b5b34a72bb4 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 8 Jun 2022 18:14:00 +0300 Subject: [PATCH 2/5] rpc: split response.Error into server/client side --- pkg/rpc/response/errors.go | 75 ++++++++++++--------- pkg/rpc/response/types.go | 12 ++-- pkg/rpc/server/server.go | 134 ++++++++++++++++++------------------- 3 files changed, 118 insertions(+), 103 deletions(-) diff --git a/pkg/rpc/response/errors.go b/pkg/rpc/response/errors.go index 53aa1d683..9c4352664 100644 --- a/pkg/rpc/response/errors.go +++ b/pkg/rpc/response/errors.go @@ -6,13 +6,17 @@ import ( ) type ( - // Error object for outputting JSON-RPC 2.0 - // errors. + // ServerError object for outputting JSON-RPC 2.0 errors on the server side. + ServerError struct { + *Error + HTTPCode int // HTTPCode won't be marshalled because Error's marshaller is used. + } + + // Error represents JSON-RPC 2.0 error type. Error struct { - Code int64 `json:"code"` - HTTPCode int `json:"-"` - Message string `json:"message"` - Data string `json:"data,omitempty"` + Code int64 `json:"code"` + Message string `json:"message"` + Data string `json:"data,omitempty"` } ) @@ -36,57 +40,65 @@ var ( ErrUnknown = NewSubmitError(-500, "Unknown error.") ) -// NewError is an Error constructor that takes Error contents from its +// NewServerError is an ServerError constructor that takes ServerError contents from its // parameters. -func NewError(code int64, httpCode int, message string, data string) *Error { - return &Error{ - Code: code, +func NewServerError(code int64, httpCode int, message string, data string) *ServerError { + return &ServerError{ + Error: &Error{ + Code: code, + Message: message, + Data: data, + }, HTTPCode: httpCode, - Message: message, - Data: data, } } // NewParseError creates a new error with code // -32700. -func NewParseError(data string) *Error { - return NewError(-32700, http.StatusBadRequest, "Parse Error", data) +func NewParseError(data string) *ServerError { + return NewServerError(-32700, http.StatusBadRequest, "Parse Error", data) } // NewInvalidRequestError creates a new error with // code -32600. -func NewInvalidRequestError(data string) *Error { - return NewError(-32600, http.StatusUnprocessableEntity, "Invalid Request", data) +func NewInvalidRequestError(data string) *ServerError { + return NewServerError(-32600, http.StatusUnprocessableEntity, "Invalid Request", data) } // NewMethodNotFoundError creates a new error with // code -32601. -func NewMethodNotFoundError(data string) *Error { - return NewError(-32601, http.StatusMethodNotAllowed, "Method not found", data) +func NewMethodNotFoundError(data string) *ServerError { + return NewServerError(-32601, http.StatusMethodNotAllowed, "Method not found", data) } // NewInvalidParamsError creates a new error with // code -32602. -func NewInvalidParamsError(data string) *Error { - return NewError(-32602, http.StatusUnprocessableEntity, "Invalid Params", data) +func NewInvalidParamsError(data string) *ServerError { + return NewServerError(-32602, http.StatusUnprocessableEntity, "Invalid Params", data) } // NewInternalServerError creates a new error with // code -32603. -func NewInternalServerError(data string) *Error { - return NewError(InternalServerErrorCode, http.StatusInternalServerError, "Internal error", data) +func NewInternalServerError(data string) *ServerError { + return NewServerError(InternalServerErrorCode, http.StatusInternalServerError, "Internal error", data) } // NewRPCError creates a new error with // code -100. -func NewRPCError(message string, data string) *Error { - return NewError(-100, http.StatusUnprocessableEntity, message, data) +func NewRPCError(message string, data string) *ServerError { + return NewServerError(-100, http.StatusUnprocessableEntity, 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, "") +func NewSubmitError(code int64, message string) *ServerError { + return NewServerError(code, http.StatusUnprocessableEntity, message, "") +} + +// WrapErrorWithData returns copy of the given error with the specified data and cause. +// It does not modify the source error. +func WrapErrorWithData(e *ServerError, data string) *ServerError { + return NewServerError(e.Code, e.HTTPCode, e.Message, data) } // Error implements the error interface. @@ -97,8 +109,11 @@ func (e *Error) Error() string { 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 string) *Error { - return NewError(e.Code, e.HTTPCode, e.Message, 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 } diff --git a/pkg/rpc/response/types.go b/pkg/rpc/response/types.go index a55bab21f..64b93020a 100644 --- a/pkg/rpc/response/types.go +++ b/pkg/rpc/response/types.go @@ -31,16 +31,18 @@ type AbstractResult interface { } // Abstract represents abstract JSON-RPC 2.0 response, it differs from Raw in -// that Result field is an interface here. +// that Result field is an interface here. It is used as a server-side response +// representation. type Abstract struct { - HeaderAndError - Result interface{} `json:"result,omitempty"` + Header + Error *ServerError `json:"error,omitempty"` + Result interface{} `json:"result,omitempty"` } // RunForErrors implements AbstractResult interface. func (a Abstract) RunForErrors(f func(jsonErr *Error)) { if a.Error != nil { - f(a.Error) + f(a.Error.Error) } } @@ -51,7 +53,7 @@ type AbstractBatch []Abstract func (ab AbstractBatch) RunForErrors(f func(jsonErr *Error)) { for _, a := range ab { if a.Error != nil { - f(a.Error) + f(a.Error.Error) } } } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 035d06dd9..b60d00e0c 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -107,7 +107,7 @@ const ( maxTransfersLimit = 1000 ) -var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *response.Error){ +var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *response.ServerError){ "calculatenetworkfee": (*Server).calculateNetworkFee, "findstates": (*Server).findStates, "getapplicationlog": (*Server).getApplicationLog, @@ -153,12 +153,12 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon "verifyproof": (*Server).verifyProof, } -var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (interface{}, *response.Error){ +var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (interface{}, *response.ServerError){ "subscribe": (*Server).subscribe, "unsubscribe": (*Server).unsubscribe, } -var invalidBlockHeightError = func(index int, height int) *response.Error { +var invalidBlockHeightError = func(index int, height int) *response.ServerError { return response.NewRPCError("Invalid block height", fmt.Sprintf("param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height)) } @@ -355,7 +355,7 @@ func (s *Server) handleRequest(req *request.Request, sub *subscriber) response.A func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract { var res interface{} - var resErr *response.Error + var resErr *response.ServerError if req.JSONRPC != request.JSONRPCVersion { return s.packResponse(req, nil, response.NewInvalidParamsError(fmt.Sprintf("problem parsing JSON: invalid version, expected 2.0 got '%s'", req.JSONRPC))) } @@ -467,23 +467,23 @@ requestloop: ws.Close() } -func (s *Server) getBestBlockHash(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBestBlockHash(_ request.Params) (interface{}, *response.ServerError) { return "0x" + s.chain.CurrentBlockHash().StringLE(), nil } -func (s *Server) getBlockCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockCount(_ request.Params) (interface{}, *response.ServerError) { return s.chain.BlockHeight() + 1, nil } -func (s *Server) getBlockHeaderCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHeaderCount(_ request.Params) (interface{}, *response.ServerError) { return s.chain.HeaderHeight() + 1, nil } -func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.ServerError) { return s.coreServer.PeerCount(), nil } -func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.Error) { +func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.ServerError) { var ( hash util.Uint256 err error @@ -502,7 +502,7 @@ func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *respon return hash, nil } -func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.ServerError) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -522,7 +522,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro return writer.Bytes(), nil } -func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.ServerError) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return nil, response.ErrInvalidParams @@ -531,7 +531,7 @@ func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response. return s.chain.GetHeaderHash(num), nil } -func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getVersion(_ request.Params) (interface{}, *response.ServerError) { port, err := s.coreServer.Port() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err)) @@ -559,7 +559,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { }, nil } -func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getPeers(_ request.Params) (interface{}, *response.ServerError) { peers := result.NewGetPeers() peers.AddUnconnected(s.coreServer.UnconnectedPeers()) peers.AddConnected(s.coreServer.ConnectedPeers()) @@ -567,7 +567,7 @@ func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) { return peers, nil } -func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.ServerError) { verbose, _ := reqParams.Value(0).GetBoolean() mp := s.chain.GetMemPool() hashList := make([]util.Uint256, 0) @@ -584,7 +584,7 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response }, nil } -func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.ServerError) { param, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -597,7 +597,7 @@ func (s *Server) validateAddress(reqParams request.Params) (interface{}, *respon } // calculateNetworkFee calculates network fee for the transaction. -func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *response.ServerError) { if len(reqParams) < 1 { return 0, response.ErrInvalidParams } @@ -651,7 +651,7 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re } // getApplicationLog returns the contract log based on the specified txid or blockid. -func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *response.ServerError) { hash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -689,7 +689,7 @@ func (s *Server) getNEP11Tokens(h util.Uint160, acc util.Uint160, bw *io.BufBinW return nil, fmt.Errorf("invalid `tokensOf` result type %s", item.String()) } -func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.ServerError) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -775,7 +775,7 @@ func (s *Server) invokeNEP11Properties(h util.Uint160, id []byte, bw *io.BufBinW return item.Value().([]stackitem.MapElement), nil } -func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.ServerError) { asset, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -811,7 +811,7 @@ func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.E return res, nil } -func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.ServerError) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -959,15 +959,15 @@ func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, i return start, end, limit, page, nil } -func (s *Server) getNEP11Transfers(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Transfers(ps request.Params) (interface{}, *response.ServerError) { return s.getTokenTransfers(ps, true) } -func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.ServerError) { return s.getTokenTransfers(ps, false) } -func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}, *response.Error) { +func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}, *response.ServerError) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1084,7 +1084,7 @@ func (s *Server) getHash(contractID int32, cache map[int32]util.Uint160) (util.U return h, nil } -func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Error) { +func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.ServerError) { var result int32 if param == nil { return 0, response.ErrInvalidParams @@ -1109,7 +1109,7 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err } // getContractScriptHashFromParam returns the contract script hash by hex contract hash, address, id or native contract name. -func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.Error) { +func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.ServerError) { var result util.Uint160 if param == nil { return result, response.ErrInvalidParams @@ -1149,7 +1149,7 @@ func makeStorageKey(id int32, key []byte) []byte { var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled") -func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getProof(ps request.Params) (interface{}, *response.ServerError) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1180,7 +1180,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { }, nil } -func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { +func (s *Server) verifyProof(ps request.Params) (interface{}, *response.ServerError) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1204,7 +1204,7 @@ func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { return vp, nil } -func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getState(ps request.Params) (interface{}, *response.ServerError) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1238,7 +1238,7 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { return res, nil } -func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { +func (s *Server) findStates(ps request.Params) (interface{}, *response.ServerError) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1332,7 +1332,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { return res, nil } -func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint160) (*state.Contract, *response.Error) { +func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint160) (*state.Contract, *response.ServerError) { csKey := makeStorageKey(native.ManagementContractID, native.MakeContractKey(csHash)) csBytes, err := s.chain.GetStateModule().GetState(root, csKey) if err != nil { @@ -1346,7 +1346,7 @@ func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint1 return contract, nil } -func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.ServerError) { var height = s.chain.BlockHeight() var stateHeight = s.chain.GetStateModule().CurrentValidatedHeight() if s.chain.GetConfig().StateRootInHeader { @@ -1358,7 +1358,7 @@ func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) }, nil } -func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.ServerError) { p := ps.Value(0) if p == nil { return nil, response.NewInvalidParamsError("missing stateroot identifier") @@ -1384,7 +1384,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) return rt, nil } -func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getStorage(ps request.Params) (interface{}, *response.ServerError) { id, rErr := s.contractIDFromParam(ps.Value(0)) if rErr == response.ErrUnknown { return nil, nil @@ -1406,7 +1406,7 @@ func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) { return []byte(item), nil } -func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.ServerError) { txHash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1436,7 +1436,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp return tx.Bytes(), nil } -func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.ServerError) { h, err := ps.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1452,7 +1452,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response // getContractState returns contract state (contract information, according to the contract script hash, // contract id or native contract name). -func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.ServerError) { scriptHash, err := s.contractScriptHashFromParam(reqParams.Value(0)) if err != nil { return nil, err @@ -1464,12 +1464,12 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, *respo return cs, nil } -func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.ServerError) { return s.chain.GetNatives(), nil } // getBlockSysFee returns the system fees of the block, based on the specified index. -func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.ServerError) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return 0, response.NewRPCError("Invalid height", "invalid block identifier") @@ -1490,7 +1490,7 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *respons } // getBlockHeader returns the corresponding block header information according to the specified script hash. -func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.ServerError) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -1516,7 +1516,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons } // getUnclaimedGas returns unclaimed GAS amount of the specified address. -func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.ServerError) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1539,7 +1539,7 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro } // getNextBlockValidators returns validators for the next block with voting status. -func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.ServerError) { var validators keys.PublicKeys validators, err := s.chain.GetNextBlockValidators() @@ -1562,7 +1562,7 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons } // getCommittee returns the current list of NEO committee members. -func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getCommittee(_ request.Params) (interface{}, *response.ServerError) { keys, err := s.chain.GetCommittee() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("can't get committee members: %s", err)) @@ -1571,7 +1571,7 @@ func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { } // invokeFunction implements the `invokeFunction` RPC call. -func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.ServerError) { tx, verbose, respErr := s.getInvokeFunctionParams(reqParams) if respErr != nil { return nil, respErr @@ -1580,7 +1580,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons } // invokeFunctionHistoric implements the `invokeFunctionHistoric` RPC call. -func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, *response.ServerError) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1595,7 +1595,7 @@ func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { +func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction.Transaction, bool, *response.ServerError) { if len(reqParams) < 2 { return nil, false, response.ErrInvalidParams } @@ -1638,7 +1638,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction } // invokescript implements the `invokescript` RPC call. -func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.ServerError) { tx, verbose, respErr := s.getInvokeScriptParams(reqParams) if respErr != nil { return nil, respErr @@ -1647,7 +1647,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. } // invokescripthistoric implements the `invokescripthistoric` RPC call. -func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *response.ServerError) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1662,7 +1662,7 @@ func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *r return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { +func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.Transaction, bool, *response.ServerError) { script, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, false, response.ErrInvalidParams @@ -1692,7 +1692,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T } // invokeContractVerify implements the `invokecontractverify` RPC call. -func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *response.ServerError) { scriptHash, tx, invocationScript, respErr := s.getInvokeContractVerifyParams(reqParams) if respErr != nil { return nil, respErr @@ -1701,7 +1701,7 @@ func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *r } // invokeContractVerifyHistoric implements the `invokecontractverifyhistoric` RPC call. -func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interface{}, *response.ServerError) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1716,7 +1716,7 @@ func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interfa return s.runScriptInVM(trigger.Verification, invocationScript, scriptHash, tx, b, false) } -func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.Uint160, *transaction.Transaction, []byte, *response.Error) { +func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.Uint160, *transaction.Transaction, []byte, *response.ServerError) { scriptHash, responseErr := s.contractScriptHashFromParam(reqParams.Value(0)) if responseErr != nil { return util.Uint160{}, nil, nil, responseErr @@ -1756,7 +1756,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U // with the specified index to perform the historic call. It also checks that // specified stateroot is stored at the specified height for further request // handling consistency. -func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) { +func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.ServerError) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) } @@ -1806,7 +1806,7 @@ func (s *Server) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) // witness invocation script in case of `verification` trigger (it pushes `verify` // arguments on stack before verification). In case of contract verification // contractScriptHash should be specified. -func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*result.Invoke, *response.Error) { +func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*result.Invoke, *response.ServerError) { var ( err error ic *interop.Context @@ -1851,7 +1851,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash } // submitBlock broadcasts a raw block over the NEO network. -func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.ServerError) { blockBytes, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, response.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err)) @@ -1877,7 +1877,7 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.E } // submitNotaryRequest broadcasts P2PNotaryRequest over the NEO network. -func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.Error) { +func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.ServerError) { if !s.chain.P2PSigExtensionsEnabled() { return nil, response.NewRPCError("P2PSignatureExtensions are disabled", "") } @@ -1894,7 +1894,7 @@ func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response. } // getRelayResult returns successful relay result or an error. -func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Error) { +func getRelayResult(err error, hash util.Uint256) (interface{}, *response.ServerError) { switch { case err == nil: return result.RelayResult{ @@ -1911,7 +1911,7 @@ func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Error) } } -func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.Error) { +func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.ServerError) { if s.oracle == nil { return nil, response.NewRPCError("Oracle is not enabled", "") } @@ -1943,7 +1943,7 @@ func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response return json.RawMessage([]byte("{}")), nil } -func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.ServerError) { if len(reqParams) < 1 { return nil, response.NewInvalidParamsError("not enough parameters") } @@ -1959,7 +1959,7 @@ func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *res } // subscribe handles subscription requests from websocket clients. -func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { +func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.ServerError) { streamName, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -2060,7 +2060,7 @@ func (s *Server) subscribeToChannel(event response.EventID) { } // unsubscribe handles unsubscription requests from websocket clients. -func (s *Server) unsubscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { +func (s *Server) unsubscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.ServerError) { id, err := reqParams.Value(0).GetInt() if err != nil || id < 0 { return nil, response.ErrInvalidParams @@ -2230,7 +2230,7 @@ drainloop: close(s.notaryRequestCh) } -func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Error) { +func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.ServerError) { num, err := param.GetInt() if err != nil { return 0, response.ErrInvalidParams @@ -2242,13 +2242,11 @@ func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Erro return num, nil } -func (s *Server) packResponse(r *request.In, result interface{}, respErr *response.Error) response.Abstract { +func (s *Server) packResponse(r *request.In, result interface{}, respErr *response.ServerError) response.Abstract { resp := response.Abstract{ - HeaderAndError: response.HeaderAndError{ - Header: response.Header{ - JSONRPC: r.JSONRPC, - ID: r.RawID, - }, + Header: response.Header{ + JSONRPC: r.JSONRPC, + ID: r.RawID, }, } if respErr != nil { @@ -2281,7 +2279,7 @@ func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { } // writeHTTPErrorResponse writes an error response to the ResponseWriter. -func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, jsonErr *response.Error) { +func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, jsonErr *response.ServerError) { resp := s.packResponse(r, nil, jsonErr) s.writeHTTPServerResponse(&request.Request{In: r}, w, resp) } From ef9eca7cceb64dcac8d6e7ec8f66313ccb989ac0 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 9 Jun 2022 18:19:01 +0300 Subject: [PATCH 3/5] rpc: unexport ServerError It's internal server thing that is not for the outside users. --- pkg/rpc/response/errors.go | 86 +++++++++++----------- pkg/rpc/response/types.go | 34 --------- pkg/rpc/server/error.go | 66 +++++++++++++++++ pkg/rpc/server/server.go | 146 ++++++++++++++++++------------------- 4 files changed, 184 insertions(+), 148 deletions(-) create mode 100644 pkg/rpc/server/error.go diff --git a/pkg/rpc/response/errors.go b/pkg/rpc/response/errors.go index 9c4352664..183371200 100644 --- a/pkg/rpc/response/errors.go +++ b/pkg/rpc/response/errors.go @@ -2,26 +2,34 @@ package response import ( "fmt" - "net/http" ) -type ( - // ServerError object for outputting JSON-RPC 2.0 errors on the server side. - ServerError struct { - *Error - HTTPCode int // HTTPCode won't be marshalled because Error's marshaller is used. - } +// Error represents JSON-RPC 2.0 error type. +type Error struct { + Code int64 `json:"code"` + Message string `json:"message"` + Data string `json:"data,omitempty"` +} - // Error represents JSON-RPC 2.0 error 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. + 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. + RPCErrorCode = -100 +) var ( // ErrInvalidParams represents a generic 'invalid parameters' error. @@ -40,65 +48,61 @@ var ( ErrUnknown = NewSubmitError(-500, "Unknown error.") ) -// NewServerError is an ServerError constructor that takes ServerError contents from its -// parameters. -func NewServerError(code int64, httpCode int, message string, data string) *ServerError { - return &ServerError{ - Error: &Error{ - Code: code, - Message: message, - Data: data, - }, - HTTPCode: httpCode, +// 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, + Message: message, + Data: data, } } // NewParseError creates a new error with code // -32700. -func NewParseError(data string) *ServerError { - return NewServerError(-32700, http.StatusBadRequest, "Parse Error", data) +func NewParseError(data string) *Error { + return NewError(BadRequestCode, "Parse Error", data) } // NewInvalidRequestError creates a new error with // code -32600. -func NewInvalidRequestError(data string) *ServerError { - return NewServerError(-32600, http.StatusUnprocessableEntity, "Invalid Request", data) +func NewInvalidRequestError(data string) *Error { + return NewError(InvalidRequestCode, "Invalid Request", data) } // NewMethodNotFoundError creates a new error with // code -32601. -func NewMethodNotFoundError(data string) *ServerError { - return NewServerError(-32601, http.StatusMethodNotAllowed, "Method not found", data) +func NewMethodNotFoundError(data string) *Error { + return NewError(MethodNotFoundCode, "Method not found", data) } // NewInvalidParamsError creates a new error with // code -32602. -func NewInvalidParamsError(data string) *ServerError { - return NewServerError(-32602, http.StatusUnprocessableEntity, "Invalid Params", data) +func NewInvalidParamsError(data string) *Error { + return NewError(InvalidParamsCode, "Invalid Params", data) } // NewInternalServerError creates a new error with // code -32603. -func NewInternalServerError(data string) *ServerError { - return NewServerError(InternalServerErrorCode, http.StatusInternalServerError, "Internal error", data) +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) *ServerError { - return NewServerError(-100, http.StatusUnprocessableEntity, message, data) +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) *ServerError { - return NewServerError(code, http.StatusUnprocessableEntity, message, "") +func NewSubmitError(code int64, message string) *Error { + 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 *ServerError, data string) *ServerError { - return NewServerError(e.Code, e.HTTPCode, e.Message, data) +func WrapErrorWithData(e *Error, data string) *Error { + return NewError(e.Code, e.Message, data) } // Error implements the error interface. diff --git a/pkg/rpc/response/types.go b/pkg/rpc/response/types.go index 64b93020a..136082768 100644 --- a/pkg/rpc/response/types.go +++ b/pkg/rpc/response/types.go @@ -24,40 +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. It is used as a server-side response -// representation. -type Abstract struct { - Header - Error *ServerError `json:"error,omitempty"` - Result interface{} `json:"result,omitempty"` -} - -// RunForErrors implements AbstractResult interface. -func (a Abstract) RunForErrors(f func(jsonErr *Error)) { - if a.Error != nil { - f(a.Error.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.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. diff --git a/pkg/rpc/server/error.go b/pkg/rpc/server/error.go new file mode 100644 index 000000000..4dd27c19f --- /dev/null +++ b/pkg/rpc/server/error.go @@ -0,0 +1,66 @@ +package server + +import ( + "net/http" + + "github.com/nspcc-dev/neo-go/pkg/rpc/response" +) + +// serverError represents RPC error response on the server side. +type serverError struct { + *response.Error + HTTPCode int // HTTPCode won't be marshalled because Error's marshaller is used. +} + +// 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 *serverError `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.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.Error) + } + } +} + +func packClientError(respErr *response.Error) *serverError { + 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 &serverError{ + Error: respErr, + HTTPCode: httpCode, + } +} diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index b60d00e0c..e89f8ddd0 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -107,7 +107,7 @@ const ( maxTransfersLimit = 1000 ) -var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *response.ServerError){ +var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *response.Error){ "calculatenetworkfee": (*Server).calculateNetworkFee, "findstates": (*Server).findStates, "getapplicationlog": (*Server).getApplicationLog, @@ -153,12 +153,12 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon "verifyproof": (*Server).verifyProof, } -var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (interface{}, *response.ServerError){ +var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (interface{}, *response.Error){ "subscribe": (*Server).subscribe, "unsubscribe": (*Server).unsubscribe, } -var invalidBlockHeightError = func(index int, height int) *response.ServerError { +var invalidBlockHeightError = func(index int, height int) *response.Error { return response.NewRPCError("Invalid block height", fmt.Sprintf("param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height)) } @@ -310,7 +310,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.log.Info("websocket connection upgrade failed", zap.Error(err)) return } - resChan := make(chan response.AbstractResult) // response.Abstract or response.AbstractBatch + resChan := make(chan abstractResult) // response.abstract or response.abstractBatch subChan := make(chan *websocket.PreparedMessage, notificationBufSize) subscr := &subscriber{writer: subChan, ws: ws} s.subsLock.Lock() @@ -340,12 +340,12 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.writeHTTPServerResponse(req, w, resp) } -func (s *Server) handleRequest(req *request.Request, sub *subscriber) response.AbstractResult { +func (s *Server) handleRequest(req *request.Request, sub *subscriber) abstractResult { if req.In != nil { req.In.Method = escapeForLog(req.In.Method) // No valid method name will be changed by it. return s.handleIn(req.In, sub) } - resp := make(response.AbstractBatch, len(req.Batch)) + resp := make(abstractBatch, len(req.Batch)) for i, in := range req.Batch { in.Method = escapeForLog(in.Method) // No valid method name will be changed by it. resp[i] = s.handleIn(&in, sub) @@ -353,9 +353,9 @@ func (s *Server) handleRequest(req *request.Request, sub *subscriber) response.A return resp } -func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract { +func (s *Server) handleIn(req *request.In, sub *subscriber) abstract { var res interface{} - var resErr *response.ServerError + var resErr *response.Error if req.JSONRPC != request.JSONRPCVersion { return s.packResponse(req, nil, response.NewInvalidParamsError(fmt.Sprintf("problem parsing JSON: invalid version, expected 2.0 got '%s'", req.JSONRPC))) } @@ -381,7 +381,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract { return s.packResponse(req, res, resErr) } -func (s *Server) handleWsWrites(ws *websocket.Conn, resChan <-chan response.AbstractResult, subChan <-chan *websocket.PreparedMessage) { +func (s *Server) handleWsWrites(ws *websocket.Conn, resChan <-chan abstractResult, subChan <-chan *websocket.PreparedMessage) { pingTicker := time.NewTicker(wsPingPeriod) eventloop: for { @@ -434,7 +434,7 @@ drainloop: } } -func (s *Server) handleWsReads(ws *websocket.Conn, resChan chan<- response.AbstractResult, subscr *subscriber) { +func (s *Server) handleWsReads(ws *websocket.Conn, resChan chan<- abstractResult, subscr *subscriber) { ws.SetReadLimit(s.wsReadLimit) err := ws.SetReadDeadline(time.Now().Add(wsPongLimit)) ws.SetPongHandler(func(string) error { return ws.SetReadDeadline(time.Now().Add(wsPongLimit)) }) @@ -467,23 +467,23 @@ requestloop: ws.Close() } -func (s *Server) getBestBlockHash(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBestBlockHash(_ request.Params) (interface{}, *response.Error) { return "0x" + s.chain.CurrentBlockHash().StringLE(), nil } -func (s *Server) getBlockCount(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlockCount(_ request.Params) (interface{}, *response.Error) { return s.chain.BlockHeight() + 1, nil } -func (s *Server) getBlockHeaderCount(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlockHeaderCount(_ request.Params) (interface{}, *response.Error) { return s.chain.HeaderHeight() + 1, nil } -func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.Error) { return s.coreServer.PeerCount(), nil } -func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.ServerError) { +func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.Error) { var ( hash util.Uint256 err error @@ -502,7 +502,7 @@ func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *respon return hash, nil } -func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Error) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -522,7 +522,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Serv return writer.Bytes(), nil } -func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return nil, response.ErrInvalidParams @@ -531,7 +531,7 @@ func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response. return s.chain.GetHeaderHash(num), nil } -func (s *Server) getVersion(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { port, err := s.coreServer.Port() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err)) @@ -559,7 +559,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.ServerErro }, nil } -func (s *Server) getPeers(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) { peers := result.NewGetPeers() peers.AddUnconnected(s.coreServer.UnconnectedPeers()) peers.AddConnected(s.coreServer.ConnectedPeers()) @@ -567,7 +567,7 @@ func (s *Server) getPeers(_ request.Params) (interface{}, *response.ServerError) return peers, nil } -func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) { verbose, _ := reqParams.Value(0).GetBoolean() mp := s.chain.GetMemPool() hashList := make([]util.Uint256, 0) @@ -584,7 +584,7 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response }, nil } -func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) { param, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -597,7 +597,7 @@ func (s *Server) validateAddress(reqParams request.Params) (interface{}, *respon } // calculateNetworkFee calculates network fee for the transaction. -func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *response.Error) { if len(reqParams) < 1 { return 0, response.ErrInvalidParams } @@ -651,7 +651,7 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re } // getApplicationLog returns the contract log based on the specified txid or blockid. -func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *response.Error) { hash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -689,7 +689,7 @@ func (s *Server) getNEP11Tokens(h util.Uint160, acc util.Uint160, bw *io.BufBinW return nil, fmt.Errorf("invalid `tokensOf` result type %s", item.String()) } -func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -775,7 +775,7 @@ func (s *Server) invokeNEP11Properties(h util.Uint160, id []byte, bw *io.BufBinW return item.Value().([]stackitem.MapElement), nil } -func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.Error) { asset, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -811,7 +811,7 @@ func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.S return res, nil } -func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -959,15 +959,15 @@ func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, i return start, end, limit, page, nil } -func (s *Server) getNEP11Transfers(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNEP11Transfers(ps request.Params) (interface{}, *response.Error) { return s.getTokenTransfers(ps, true) } -func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.Error) { return s.getTokenTransfers(ps, false) } -func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}, *response.ServerError) { +func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1084,7 +1084,7 @@ func (s *Server) getHash(contractID int32, cache map[int32]util.Uint160) (util.U return h, nil } -func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.ServerError) { +func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Error) { var result int32 if param == nil { return 0, response.ErrInvalidParams @@ -1109,7 +1109,7 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Ser } // getContractScriptHashFromParam returns the contract script hash by hex contract hash, address, id or native contract name. -func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.ServerError) { +func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.Error) { var result util.Uint160 if param == nil { return result, response.ErrInvalidParams @@ -1149,7 +1149,7 @@ func makeStorageKey(id int32, key []byte) []byte { var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled") -func (s *Server) getProof(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1180,7 +1180,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.ServerError }, nil } -func (s *Server) verifyProof(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1204,7 +1204,7 @@ func (s *Server) verifyProof(ps request.Params) (interface{}, *response.ServerEr return vp, nil } -func (s *Server) getState(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1238,7 +1238,7 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.ServerError return res, nil } -func (s *Server) findStates(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1332,7 +1332,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.ServerErr return res, nil } -func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint160) (*state.Contract, *response.ServerError) { +func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint160) (*state.Contract, *response.Error) { csKey := makeStorageKey(native.ManagementContractID, native.MakeContractKey(csHash)) csBytes, err := s.chain.GetStateModule().GetState(root, csKey) if err != nil { @@ -1346,7 +1346,7 @@ func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint1 return contract, nil } -func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) { var height = s.chain.BlockHeight() var stateHeight = s.chain.GetStateModule().CurrentValidatedHeight() if s.chain.GetConfig().StateRootInHeader { @@ -1358,7 +1358,7 @@ func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Server }, nil } -func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) { p := ps.Value(0) if p == nil { return nil, response.NewInvalidParamsError("missing stateroot identifier") @@ -1384,7 +1384,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.ServerE return rt, nil } -func (s *Server) getStorage(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) { id, rErr := s.contractIDFromParam(ps.Value(0)) if rErr == response.ErrUnknown { return nil, nil @@ -1406,7 +1406,7 @@ func (s *Server) getStorage(ps request.Params) (interface{}, *response.ServerErr return []byte(item), nil } -func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.Error) { txHash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1436,7 +1436,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp return tx.Bytes(), nil } -func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.Error) { h, err := ps.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1452,7 +1452,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response // getContractState returns contract state (contract information, according to the contract script hash, // contract id or native contract name). -func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) { scriptHash, err := s.contractScriptHashFromParam(reqParams.Value(0)) if err != nil { return nil, err @@ -1464,12 +1464,12 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, *respo return cs, nil } -func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.Error) { return s.chain.GetNatives(), nil } // getBlockSysFee returns the system fees of the block, based on the specified index. -func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return 0, response.NewRPCError("Invalid height", "invalid block identifier") @@ -1490,7 +1490,7 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *respons } // getBlockHeader returns the corresponding block header information according to the specified script hash. -func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.Error) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -1516,7 +1516,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons } // getUnclaimedGas returns unclaimed GAS amount of the specified address. -func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1539,7 +1539,7 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Serv } // getNextBlockValidators returns validators for the next block with voting status. -func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.Error) { var validators keys.PublicKeys validators, err := s.chain.GetNextBlockValidators() @@ -1562,7 +1562,7 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons } // getCommittee returns the current list of NEO committee members. -func (s *Server) getCommittee(_ request.Params) (interface{}, *response.ServerError) { +func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { keys, err := s.chain.GetCommittee() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("can't get committee members: %s", err)) @@ -1571,7 +1571,7 @@ func (s *Server) getCommittee(_ request.Params) (interface{}, *response.ServerEr } // invokeFunction implements the `invokeFunction` RPC call. -func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) { tx, verbose, respErr := s.getInvokeFunctionParams(reqParams) if respErr != nil { return nil, respErr @@ -1580,7 +1580,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons } // invokeFunctionHistoric implements the `invokeFunctionHistoric` RPC call. -func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1595,7 +1595,7 @@ func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction.Transaction, bool, *response.ServerError) { +func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { if len(reqParams) < 2 { return nil, false, response.ErrInvalidParams } @@ -1638,7 +1638,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction } // invokescript implements the `invokescript` RPC call. -func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.Error) { tx, verbose, respErr := s.getInvokeScriptParams(reqParams) if respErr != nil { return nil, respErr @@ -1647,7 +1647,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. } // invokescripthistoric implements the `invokescripthistoric` RPC call. -func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1662,7 +1662,7 @@ func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *r return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.Transaction, bool, *response.ServerError) { +func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { script, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, false, response.ErrInvalidParams @@ -1692,7 +1692,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T } // invokeContractVerify implements the `invokecontractverify` RPC call. -func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *response.Error) { scriptHash, tx, invocationScript, respErr := s.getInvokeContractVerifyParams(reqParams) if respErr != nil { return nil, respErr @@ -1701,7 +1701,7 @@ func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *r } // invokeContractVerifyHistoric implements the `invokecontractverifyhistoric` RPC call. -func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1716,7 +1716,7 @@ func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interfa return s.runScriptInVM(trigger.Verification, invocationScript, scriptHash, tx, b, false) } -func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.Uint160, *transaction.Transaction, []byte, *response.ServerError) { +func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.Uint160, *transaction.Transaction, []byte, *response.Error) { scriptHash, responseErr := s.contractScriptHashFromParam(reqParams.Value(0)) if responseErr != nil { return util.Uint160{}, nil, nil, responseErr @@ -1756,7 +1756,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U // with the specified index to perform the historic call. It also checks that // specified stateroot is stored at the specified height for further request // handling consistency. -func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.ServerError) { +func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) } @@ -1806,7 +1806,7 @@ func (s *Server) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, error) // witness invocation script in case of `verification` trigger (it pushes `verify` // arguments on stack before verification). In case of contract verification // contractScriptHash should be specified. -func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*result.Invoke, *response.ServerError) { +func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash util.Uint160, tx *transaction.Transaction, b *block.Block, verbose bool) (*result.Invoke, *response.Error) { var ( err error ic *interop.Context @@ -1851,7 +1851,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash } // submitBlock broadcasts a raw block over the NEO network. -func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) { blockBytes, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, response.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err)) @@ -1877,7 +1877,7 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.S } // submitNotaryRequest broadcasts P2PNotaryRequest over the NEO network. -func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.Error) { if !s.chain.P2PSigExtensionsEnabled() { return nil, response.NewRPCError("P2PSignatureExtensions are disabled", "") } @@ -1894,7 +1894,7 @@ func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response. } // getRelayResult returns successful relay result or an error. -func getRelayResult(err error, hash util.Uint256) (interface{}, *response.ServerError) { +func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Error) { switch { case err == nil: return result.RelayResult{ @@ -1911,7 +1911,7 @@ func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Server } } -func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.ServerError) { +func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.Error) { if s.oracle == nil { return nil, response.NewRPCError("Oracle is not enabled", "") } @@ -1943,7 +1943,7 @@ func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response return json.RawMessage([]byte("{}")), nil } -func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.ServerError) { +func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) { if len(reqParams) < 1 { return nil, response.NewInvalidParamsError("not enough parameters") } @@ -1959,7 +1959,7 @@ func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *res } // subscribe handles subscription requests from websocket clients. -func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.ServerError) { +func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { streamName, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -2060,7 +2060,7 @@ func (s *Server) subscribeToChannel(event response.EventID) { } // unsubscribe handles unsubscription requests from websocket clients. -func (s *Server) unsubscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.ServerError) { +func (s *Server) unsubscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { id, err := reqParams.Value(0).GetInt() if err != nil || id < 0 { return nil, response.ErrInvalidParams @@ -2230,7 +2230,7 @@ drainloop: close(s.notaryRequestCh) } -func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.ServerError) { +func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Error) { num, err := param.GetInt() if err != nil { return 0, response.ErrInvalidParams @@ -2242,15 +2242,15 @@ func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Serv return num, nil } -func (s *Server) packResponse(r *request.In, result interface{}, respErr *response.ServerError) response.Abstract { - resp := response.Abstract{ +func (s *Server) packResponse(r *request.In, result interface{}, respErr *response.Error) abstract { + resp := abstract{ Header: response.Header{ JSONRPC: r.JSONRPC, ID: r.RawID, }, } if respErr != nil { - resp.Error = respErr + resp.Error = packClientError(respErr) } else { resp.Result = result } @@ -2279,18 +2279,18 @@ func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { } // writeHTTPErrorResponse writes an error response to the ResponseWriter. -func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, jsonErr *response.ServerError) { +func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, jsonErr *response.Error) { resp := s.packResponse(r, nil, jsonErr) s.writeHTTPServerResponse(&request.Request{In: r}, w, resp) } -func (s *Server) writeHTTPServerResponse(r *request.Request, w http.ResponseWriter, resp response.AbstractResult) { +func (s *Server) writeHTTPServerResponse(r *request.Request, w http.ResponseWriter, resp abstractResult) { // Errors can happen in many places and we can only catch ALL of them here. resp.RunForErrors(func(jsonErr *response.Error) { s.logRequestError(r, jsonErr) }) if r.In != nil { - resp := resp.(response.Abstract) + resp := resp.(abstract) if resp.Error != nil { w.WriteHeader(resp.Error.HTTPCode) } From 6434404081456614ba0735c216787886f3034f24 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 10 Jun 2022 16:26:33 +0300 Subject: [PATCH 4/5] rpc: extend the list of predefined RPC errors Add a few the most common ones. --- pkg/rpc/response/errors.go | 10 ++++++++++ pkg/rpc/server/server.go | 12 ++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/pkg/rpc/response/errors.go b/pkg/rpc/response/errors.go index 183371200..21a50de0b 100644 --- a/pkg/rpc/response/errors.go +++ b/pkg/rpc/response/errors.go @@ -34,6 +34,16 @@ const ( var ( // ErrInvalidParams represents a generic 'invalid parameters' error. 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. diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index e89f8ddd0..a024a96c7 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -671,7 +671,7 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *resp appExecResults, err := s.chain.GetAppExecResults(hash, trigger.All) if err != nil { - return nil, response.NewRPCError("Unknown transaction or block", fmt.Sprintf("failed to locate application log: %s", err)) + return nil, response.WrapErrorWithData(response.ErrUnknownScriptContainer, fmt.Sprintf("failed to locate application log: %s", err)) } return result.NewApplicationLog(hash, appExecResults, trig), nil } @@ -1379,7 +1379,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) } } if err != nil { - return nil, response.NewRPCError("Unknown state root", "") + return nil, response.ErrUnknownStateRoot } return rt, nil } @@ -1413,7 +1413,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp } tx, height, err := s.chain.GetTransaction(txHash) if err != nil { - return nil, response.NewRPCError("Unknown transaction", "") + return nil, response.ErrUnknownTransaction } if v, _ := reqParams.Value(1).GetBoolean(); v { if height == math.MaxUint32 { @@ -1444,7 +1444,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response _, height, err := s.chain.GetTransaction(h) if err != nil || height == math.MaxUint32 { - return nil, response.NewRPCError("Unknown transaction", "") + return nil, response.ErrUnknownTransaction } return height, nil @@ -1478,7 +1478,7 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *respons headerHash := s.chain.GetHeaderHash(num) block, errBlock := s.chain.GetBlock(headerHash) if errBlock != nil { - return 0, response.NewRPCError("Unknown block", "") + return 0, response.ErrUnknownBlock } var blockSysFee int64 @@ -1500,7 +1500,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons verbose, _ := reqParams.Value(1).GetBoolean() h, err := s.chain.GetHeader(hash) if err != nil { - return nil, response.NewRPCError("Unknown header", "") + return nil, response.ErrUnknownHeader } if verbose { From ea6ddbee5b9286647705ecc17ec1290ad0a2c8f2 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 10 Jun 2022 16:26:33 +0300 Subject: [PATCH 5/5] rpc: get rid of erverError type Retrieve error's HTTP code in a separate method. --- pkg/rpc/server/error.go | 21 ++++++--------------- pkg/rpc/server/server.go | 4 ++-- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/pkg/rpc/server/error.go b/pkg/rpc/server/error.go index 4dd27c19f..8c5223224 100644 --- a/pkg/rpc/server/error.go +++ b/pkg/rpc/server/error.go @@ -6,12 +6,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpc/response" ) -// serverError represents RPC error response on the server side. -type serverError struct { - *response.Error - HTTPCode int // HTTPCode won't be marshalled because Error's marshaller is used. -} - // abstractResult is an interface which represents either single JSON-RPC 2.0 response // or batch JSON-RPC 2.0 response. type abstractResult interface { @@ -22,14 +16,14 @@ type abstractResult interface { // representation. type abstract struct { response.Header - Error *serverError `json:"error,omitempty"` - Result interface{} `json:"result,omitempty"` + 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.Error) + f(a.Error) } } @@ -40,12 +34,12 @@ type abstractBatch []abstract func (ab abstractBatch) RunForErrors(f func(jsonErr *response.Error)) { for _, a := range ab { if a.Error != nil { - f(a.Error.Error) + f(a.Error) } } } -func packClientError(respErr *response.Error) *serverError { +func getHTTPCodeForError(respErr *response.Error) int { var httpCode int switch respErr.Code { case response.BadRequestCode: @@ -59,8 +53,5 @@ func packClientError(respErr *response.Error) *serverError { default: httpCode = http.StatusUnprocessableEntity } - return &serverError{ - Error: respErr, - HTTPCode: httpCode, - } + return httpCode } diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index a024a96c7..91eabe359 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -2250,7 +2250,7 @@ func (s *Server) packResponse(r *request.In, result interface{}, respErr *respon }, } if respErr != nil { - resp.Error = packClientError(respErr) + resp.Error = respErr } else { resp.Result = result } @@ -2292,7 +2292,7 @@ func (s *Server) writeHTTPServerResponse(r *request.Request, w http.ResponseWrit if r.In != nil { resp := resp.(abstract) if resp.Error != nil { - w.WriteHeader(resp.Error.HTTPCode) + w.WriteHeader(getHTTPCodeForError(resp.Error)) } } w.Header().Set("Content-Type", "application/json; charset=utf-8")