diff --git a/pkg/neorpc/errors.go b/pkg/neorpc/errors.go index 7ed90994c8..df88b7efd2 100644 --- a/pkg/neorpc/errors.go +++ b/pkg/neorpc/errors.go @@ -30,33 +30,95 @@ const ( const ( // RPCErrorCode is returned on RPC request processing error. RPCErrorCode = -100 + // RPCErrorUnknownBlockCode is returned on RPC request processing error: Unknown block + RPCErrorUnknownBlockCode = -101 + // RPCErrorUnknownContractCode is returned on RPC request processing error: Unknown contract + RPCErrorUnknownContractCode = -102 + // RPCErrorUnknownTransactionCode is returned on RPC request processing error: Unknown transaction + RPCErrorUnknownTransactionCode = -103 + // RPCErrorUnknownStorageItemCode is returned on RPC request processing error: Unknown storage item + RPCErrorUnknownStorageItemCode = -104 + // RPCErrorUnknownScriptContainerCode is returned on RPC request processing error: Unknown script container + RPCErrorUnknownScriptContainerCode = -105 + // RPCErrorUnknownStateRootCode is returned on RPC request processing error: Unknown state root + RPCErrorUnknownStateRootCode = -106 + // RPCErrorUnknownHeaderCode is returned on RPC request processing error: Unknown header + RPCErrorUnknownHeaderCode = -107 ) 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", "") + ErrUnknownBlock = NewError(RPCErrorUnknownBlockCode, "Unknown block", "") + // ErrUnknownContract is returned when requested unknown contract + ErrUnknownContract = NewError(RPCErrorUnknownContractCode, "Unknown contract", "") // 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", "") + ErrUnknownTransaction = NewError(RPCErrorUnknownTransactionCode, "Unknown transaction", "") + // ErrUnknownStorageItem is returned when requested unknown storage item + ErrUnknownStorageItem = NewError(RPCErrorUnknownStorageItemCode, "Unknown storage item", "") // ErrUnknownScriptContainer is returned when requested block or transaction is not found. - ErrUnknownScriptContainer = NewError(RPCErrorCode, "Unknown script container", "") + ErrUnknownScriptContainer = NewError(RPCErrorUnknownScriptContainerCode, "Unknown script container", "") // ErrUnknownStateRoot is returned when requested state root is not found. - ErrUnknownStateRoot = NewError(RPCErrorCode, "Unknown state root", "") + ErrUnknownStateRoot = NewError(RPCErrorUnknownStateRootCode, "Unknown state root", "") + // ErrUnknownHeader is returned when requested header is not found. + ErrUnknownHeader = NewError(RPCErrorUnknownHeaderCode, "Unknown header", "") + + // ErrInvalidHeight represents SubmitError with code -201. + ErrInvalidHeight = NewSubmitError(-201, "Invalid height") + // ErrInvalidVerificationFunction represents SubmitError with code -202. + ErrInvalidVerificationFunction = NewSubmitError(-202, "Invalid verification function") + + // ErrUnknown represents SubmitError with code -500. + ErrUnknown = NewSubmitError(-500, "Unclassified inventory verification error") // ErrAlreadyExists represents SubmitError with code -501. - ErrAlreadyExists = NewSubmitError(-501, "Block or transaction already exists and cannot be sent repeatedly.") + ErrAlreadyExists = NewSubmitError(-501, "Inventory already exists on chain") // ErrOutOfMemory represents SubmitError with code -502. - ErrOutOfMemory = NewSubmitError(-502, "The memory pool is full and no more transactions can be sent.") + ErrOutOfMemory = NewSubmitError(-502, "The memory pool is full and no more transactions can be sent") // ErrUnableToVerify represents SubmitError with code -503. - ErrUnableToVerify = NewSubmitError(-503, "The block cannot be validated.") + ErrUnableToVerify = NewSubmitError(-503, "Transaction already exists in the memory pool") // ErrValidationFailed represents SubmitError with code -504. - ErrValidationFailed = NewSubmitError(-504, "Block or transaction validation failed.") + ErrValidationFailed = NewSubmitError(-504, "Validation failed") // ErrPolicyFail represents SubmitError with code -505. - ErrPolicyFail = NewSubmitError(-505, "One of the Policy filters failed.") - // ErrUnknown represents SubmitError with code -500. - ErrUnknown = NewSubmitError(-500, "Unknown error.") + ErrPolicyFail = NewSubmitError(-505, "One of the Policy filters failed") + // ErrInvalidScript represents SubmitError with code -506. + ErrInvalidScript = NewSubmitError(-506, "Invalid script") + // ErrTransactionAttr represents SubmitError with code -507. + ErrTransactionAttr = NewSubmitError(-507, "Invalid transaction attribute") + // ErrInvalidSignature represents SubmitError with code -508. + ErrInvalidSignature = NewSubmitError(-508, "Invalid signature") + // ErrInvalidSize represents SubmitError with code -509. + ErrInvalidSize = NewSubmitError(-509, "Invalid inventory size") + // ErrExpiredTransaction represents SubmitError with code -510. + ErrExpiredTransaction = NewSubmitError(-510, "Expired transaction") + // ErrInsufficientFunds represents SubmitError with code -511. + ErrInsufficientFunds = NewSubmitError(-511, "Insufficient funds") + + // ErrOracleNotRun represents SubmitError with code -601. + ErrOracleNotRun = NewSubmitError(-601, "Oracle service is not running") + // ErrOracleFinished represents SubmitError with code -602. + ErrOracleFinished = NewSubmitError(-602, "Oracle request has already been finished") + // ErrOracleNotFound represents SubmitError with code -603. + ErrOracleNotFound = NewSubmitError(-603, "Oracle request is not found") + // ErrOracleNotDesignatedNode represents SubmitError with code -604. + ErrOracleNotDesignatedNode = NewSubmitError(-604, "Not a designated oracle node") + + // ErrOldState represents SubmitError with code -701. + ErrOldState = NewSubmitError(-701, "Old state requests are not supported") + // ErrProof represents SubmitError with code -702. + ErrProof = NewSubmitError(-702, "Invalid proof") + + // ErrNotarySvcNotRun represents SubmitError with code -801. + ErrNotarySvcNotRun = NewSubmitError(-801, "Notary service is not running") + // ErrNotaryFallback represents SubmitError with code -802. + ErrNotaryFallback = NewSubmitError(-802, "Invalid fallback transaction sender") + // ErrNotaryUnableToVerify represents SubmitError with code -803. + ErrNotaryUnableToVerify = NewSubmitError(-803, "Fallback transaction is valid after deposit is unlocked") + // ErrNotaryNode represents SubmitError with code -804. + ErrNotaryNode = NewSubmitError(-804, "Not a designated notary node") + // ErrNotarySignature represents SubmitError with code -805. + ErrNotarySignature = NewSubmitError(-805, "Invalid notary request signature") ) // NewError is an Error constructor that takes Error contents from its parameters. diff --git a/pkg/services/rpcsrv/error.go b/pkg/services/rpcsrv/error.go index 89fb645387..1a7d29c623 100644 --- a/pkg/services/rpcsrv/error.go +++ b/pkg/services/rpcsrv/error.go @@ -44,7 +44,9 @@ func getHTTPCodeForError(respErr *neorpc.Error) int { switch respErr.Code { case neorpc.BadRequestCode: httpCode = http.StatusBadRequest - case neorpc.InvalidRequestCode, neorpc.RPCErrorCode, neorpc.InvalidParamsCode: + case neorpc.InvalidRequestCode, neorpc.RPCErrorCode, neorpc.InvalidParamsCode, neorpc.RPCErrorUnknownBlockCode, + neorpc.RPCErrorUnknownContractCode, neorpc.RPCErrorUnknownTransactionCode, neorpc.RPCErrorUnknownStorageItemCode, + neorpc.RPCErrorUnknownScriptContainerCode, neorpc.RPCErrorUnknownStateRootCode, neorpc.RPCErrorUnknownHeaderCode: httpCode = http.StatusUnprocessableEntity case neorpc.MethodNotFoundCode: httpCode = http.StatusMethodNotAllowed diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index b57d227a55..0bdf2a4ed6 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -250,10 +250,6 @@ var rpcWsHandlers = map[string]func(*Server, params.Params, *subscriber) (any, * "unsubscribe": (*Server).unsubscribe, } -var invalidBlockHeightError = func(index int, height int) *neorpc.Error { - return neorpc.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)) -} - // New creates a new Server struct. func New(chain Ledger, conf config.RPC, coreServer *network.Server, orc OracleHandler, log *zap.Logger, errChan chan<- error) Server { @@ -782,7 +778,7 @@ func (s *Server) getBlock(reqParams params.Params) (any, *neorpc.Error) { block, err := s.chain.GetBlock(hash) if err != nil { - return nil, neorpc.NewRPCError("Failed to get block", err.Error()) + return nil, neorpc.WrapErrorWithData(neorpc.ErrUnknownBlock, err.Error()) } if v, _ := reqParams.Value(1).GetBoolean(); v { @@ -800,7 +796,7 @@ func (s *Server) getBlock(reqParams params.Params) (any, *neorpc.Error) { func (s *Server) getBlockHash(reqParams params.Params) (any, *neorpc.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { - return nil, neorpc.ErrInvalidParams + return nil, err } return s.chain.GetHeaderHash(num), nil @@ -899,11 +895,11 @@ func (s *Server) calculateNetworkFee(reqParams params.Params) (any, *neorpc.Erro if len(w.VerificationScript) == 0 { // Contract-based verification cs := s.chain.GetContractState(signer.Account) if cs == nil { - return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("signer %d has no verification script and no deployed contract", i)) + return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidScript, fmt.Sprintf("signer %d has no verification script and no deployed contract", i)) } md := cs.Manifest.ABI.GetMethod(manifest.MethodVerify, -1) if md == nil || md.ReturnType != smartcontract.BoolType { - return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("signer %d has no verify method in deployed contract", i)) + return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidScript, fmt.Sprintf("signer %d has no verify method in deployed contract", i)) } paramz = md.Parameters // Might as well have none params and it's OK. } else { // Regular signature verification. @@ -1425,7 +1421,7 @@ func (s *Server) contractIDFromParam(param *params.Param) (int32, *neorpc.Error) if scriptHash, err := param.GetUint160FromHex(); err == nil { cs := s.chain.GetContractState(scriptHash) if cs == nil { - return 0, neorpc.ErrUnknown + return 0, neorpc.ErrUnknownContract } result = cs.ID } else { @@ -1468,7 +1464,7 @@ func (s *Server) contractScriptHashFromParam(param *params.Param) (util.Uint160, } result, err = s.chain.GetContractScriptHash(int32(id)) if err != nil { - return result, neorpc.NewRPCError("Unknown contract", "") + return result, neorpc.ErrUnknownContract } return result, nil } @@ -1484,7 +1480,7 @@ var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enable func (s *Server) getProof(ps params.Params) (any, *neorpc.Error) { if s.chain.GetConfig().Ledger.KeepOnlyLatestState { - return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrOldState, fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) } root, err := ps.Value(0).GetUint256() if err != nil { @@ -1515,7 +1511,7 @@ func (s *Server) getProof(ps params.Params) (any, *neorpc.Error) { func (s *Server) verifyProof(ps params.Params) (any, *neorpc.Error) { if s.chain.GetConfig().Ledger.KeepOnlyLatestState { - return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrOldState, fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) } root, err := ps.Value(0).GetUint256() if err != nil { @@ -1527,7 +1523,7 @@ func (s *Server) verifyProof(ps params.Params) (any, *neorpc.Error) { } var p result.ProofWithKey if err := p.FromString(proofStr); err != nil { - return nil, neorpc.ErrInvalidParams + return nil, neorpc.ErrProof } vp := new(result.VerifyProof) val, ok := mpt.VerifyProof(root, p.Key, p.Proof) @@ -1548,7 +1544,7 @@ func (s *Server) getState(ps params.Params) (any, *neorpc.Error) { return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) } if !curr.Root.Equals(root) { - return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'getstate' is not supported for old states: %s", errKeepOnlyLatestState)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrOldState, fmt.Sprintf("'getstate' is not supported for old states: %s", errKeepOnlyLatestState)) } } csHash, err := ps.Value(1).GetUint160FromHex() @@ -1582,7 +1578,7 @@ func (s *Server) findStates(ps params.Params) (any, *neorpc.Error) { return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) } if !curr.Root.Equals(root) { - return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'findstates' is not supported for old states: %s", errKeepOnlyLatestState)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrOldState, fmt.Sprintf("'findstates' is not supported for old states: %s", errKeepOnlyLatestState)) } } csHash, err := ps.Value(1).GetUint160FromHex() @@ -1669,7 +1665,7 @@ 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, neorpc.NewRPCError("Failed to get historical contract state", err.Error()) + return nil, neorpc.WrapErrorWithData(neorpc.ErrUnknownContract, fmt.Sprintf("Failed to get historical contract state: %s", err.Error())) } contract := new(state.Contract) err = stackitem.DeserializeConvertible(csBytes, contract) @@ -1719,9 +1715,6 @@ func (s *Server) getStateRoot(ps params.Params) (any, *neorpc.Error) { func (s *Server) getStorage(ps params.Params) (any, *neorpc.Error) { id, rErr := s.contractIDFromParam(ps.Value(0)) - if rErr == neorpc.ErrUnknown { - return nil, nil - } if rErr != nil { return nil, rErr } @@ -1733,7 +1726,7 @@ func (s *Server) getStorage(ps params.Params) (any, *neorpc.Error) { item := s.chain.GetStorageItem(id, key) if item == nil { - return "", nil + return "", neorpc.ErrUnknownStorageItem } return []byte(item), nil @@ -1801,7 +1794,7 @@ func (s *Server) getContractState(reqParams params.Params) (any, *neorpc.Error) } cs := s.chain.GetContractState(scriptHash) if cs == nil { - return nil, neorpc.NewRPCError("Unknown contract", "") + return nil, neorpc.ErrUnknownContract } return cs, nil } @@ -1814,7 +1807,7 @@ func (s *Server) getNativeContracts(_ params.Params) (any, *neorpc.Error) { func (s *Server) getBlockSysFee(reqParams params.Params) (any, *neorpc.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { - return 0, neorpc.NewRPCError("Invalid height", "invalid block identifier") + return 0, err } headerHash := s.chain.GetHeaderHash(num) @@ -2097,7 +2090,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Ui 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, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, err.Error()) + return util.Uint160{}, nil, nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidVerificationFunction, err.Error()) } if len(args) > 0 { err := params.ExpandArrayIntoScript(bw.BinWriter, args) @@ -2129,7 +2122,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Ui // handling consistency. func (s *Server) getHistoricParams(reqParams params.Params) (uint32, *neorpc.Error) { if s.chain.GetConfig().Ledger.KeepOnlyLatestState { - return 0, neorpc.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) + return 0, neorpc.WrapErrorWithData(neorpc.ErrOldState, fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) } if len(reqParams) < 1 { return 0, neorpc.ErrInvalidParams @@ -2463,7 +2456,7 @@ func getRelayResult(err error, hash util.Uint256) (any, *neorpc.Error) { func (s *Server) submitOracleResponse(ps params.Params) (any, *neorpc.Error) { oracle := s.oracle.Load().(*OracleHandler) if oracle == nil || *oracle == nil { - return nil, neorpc.NewRPCError("Oracle is not enabled", "") + return nil, neorpc.ErrOracleNotRun } var pub *keys.PublicKey pubBytes, err := ps.Value(0).GetBytesBase64() @@ -2479,15 +2472,15 @@ func (s *Server) submitOracleResponse(ps params.Params) (any, *neorpc.Error) { } txSig, err := ps.Value(2).GetBytesBase64() if err != nil { - return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("tx signature is missing: %s", err)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidSignature, fmt.Sprintf("tx signature is missing: %s", err)) } msgSig, err := ps.Value(3).GetBytesBase64() if err != nil { - return nil, neorpc.NewInvalidParamsError(fmt.Sprintf("msg signature is missing: %s", err)) + return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidSignature, 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, neorpc.NewRPCError("Invalid request signature", "") + return nil, neorpc.ErrInvalidSignature } (*oracle).AddResponse(pub, uint64(reqID), txSig) return json.RawMessage([]byte("{}")), nil @@ -2801,7 +2794,7 @@ func (s *Server) blockHeightFromParam(param *params.Param) (uint32, *neorpc.Erro } if num < 0 || int64(num) > int64(s.chain.BlockHeight()) { - return 0, invalidBlockHeightError(0, num) + return 0, neorpc.WrapErrorWithData(neorpc.ErrInvalidHeight, 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", 0, num)) } return uint32(num), nil }