neorpc: add error codes and response errors

According to proposal:
https://github.com/neo-project/proposals/pull/156

Close #2248

Signed-off-by: Tatiana Nesterenko <tatiana@nspcc.io>
This commit is contained in:
Tatiana Nesterenko 2023-08-14 17:43:19 +01:00
parent 3abddc78c0
commit 31ceb568cb
4 changed files with 1067 additions and 566 deletions

View file

@ -27,36 +27,232 @@ const (
)
// RPC error codes defined by the Neo JSON-RPC specification extension.
// Codes for missing items.
const (
// RPCErrorCode is returned on RPC request processing error.
RPCErrorCode = -100
// ErrUnknownBlockCode is returned from a call that accepts as a parameter or searches for a header or a block
// as a part of its job can't find it.
ErrUnknownBlockCode = -101
// ErrUnknownContractCode is returned from a call that accepts as a parameter or searches for a contract
// as a part of its job can't find it.
ErrUnknownContractCode = -102
// ErrUnknownTransactionCode is returned from a call that accepts as a parameter or searches for a transaction
// as a part of its job can't find it.
ErrUnknownTransactionCode = -103
// ErrUnknownStorageItemCode is returned from a call that looks for an item in the contract storage
// as part of its job can't find it.
ErrUnknownStorageItemCode = -104
// ErrUnknownScriptContainerCode is returned from a call that accepts as a parameter or searches for a script
// container (a block or transaction) as a part of its job can't find it
// (this error generalizes -101 and -103 in cases where it's needed).
ErrUnknownScriptContainerCode = -105
// ErrUnknownStateRootCode is returned from a call that accepts as a parameter or searches for a state root
// as a part of its job can't find it.
ErrUnknownStateRootCode = -106
// ErrUnknownSessionCode is returned from a call that accepts as a parameter or searches for an iterator session
// as a part of its job can't find it.
ErrUnknownSessionCode = -107
// ErrUnknownIteratorCode is returned from a call that accepts as a parameter or searches for a session iterator
// as a part of its job can't find it.
ErrUnknownIteratorCode = -108
// ErrUnknownHeightCode is returned if block or header height passed as parameter or calculated during call
// execution is not correct (out of the range known to the node).
ErrUnknownHeightCode = -109
)
// Codes for calls that use a wallet (-300...-304) can be returned by the C# RPC server only,
// see the https://github.com/nspcc-dev/neo-go/blob/master/docs/rpc.md#unsupported-methods.
const (
// ErrInsufficientFundsWalletCode is returned if transaction that sends some assets can't be created
// because it fails. Can be returned only by the C# RPC server.
ErrInsufficientFundsWalletCode = -300
// ErrWalletFeeLimitCode is returned if transaction requires more network fee to be paid
// than is allowed by settings. Can be returned only by the C# RPC server.
ErrWalletFeeLimitCode = -301
// ErrNoOpenedWalletCode is returned if server doesn't have any opened wallet to operate with.
// Can be returned only by the C# RPC server.
ErrNoOpenedWalletCode = -302
// ErrWalletNotFoundCode is returned if specified (or configured) wallet file path is invalid.
// Can be returned only by the C# RPC server.
ErrWalletNotFoundCode = -303
// ErrWalletNotSupportedCode is returned if specified (or configured) file can't be opened as a wallet.
// Can be returned only by the C# RPC server.
ErrWalletNotSupportedCode = -304
)
// Inventory verification or verification script errors.
const (
// ErrVerificationFailedCode is returned on anything that can't be expressed by other codes.
// It is an unclassified inventory verification error.
ErrVerificationFailedCode = -500
// ErrAlreadyExistsCode is returned if block or transaction is already accepted and processed on chain.
ErrAlreadyExistsCode = -501
// ErrMempoolCapReachedCode is returned if no more transactions can be accepted into the memory pool
// (unless they have a priority) as its full capacity is reached.
ErrMempoolCapReachedCode = -502
// ErrAlreadyInPoolCode is returned if transaction is already pooled, but not yet accepted into a block.
ErrAlreadyInPoolCode = -503
// ErrInsufficientNetworkFeeCode is returned if transaction has incorrect (too small per Policy setting)
// network fee value.
ErrInsufficientNetworkFeeCode = -504
// ErrPolicyFailedCode is returned from a call denied by the Policy contract (one of signers is blocked) or
// if one of the Policy filters failed.
ErrPolicyFailedCode = -505
// ErrInvalidScriptCode is returned if transaction contains incorrect executable script.
ErrInvalidScriptCode = -506
// ErrInvalidAttributeCode is returned if transaction contains an invalid attribute.
ErrInvalidAttributeCode = -507
// ErrInvalidSignatureCode is returned if one of the verification scripts failed.
ErrInvalidSignatureCode = -508
// ErrInvalidSizeCode is returned if transaction or its script is too big.
ErrInvalidSizeCode = -509
// ErrExpiredTransactionCode is returned if transaction's ValidUntilBlock value is already in the past.
ErrExpiredTransactionCode = -510
// ErrInsufficientFundsCode is returned if sender doesn't have enough GAS to pay for all currently pooled transactions.
ErrInsufficientFundsCode = -511
// ErrInvalidVerificationFunctionCode is returned if contract doesn't have a verify method or
// this method doesn't return proper value.
ErrInvalidVerificationFunctionCode = -512
)
// Errors related to node configuration and various services.
const (
// ErrSessionsDisabledCode is returned if iterator session support is not enabled on the server.
ErrSessionsDisabledCode = -601
// ErrOracleDisabledCode is returned if Oracle service is not enabled in the configuration (service is not running).
ErrOracleDisabledCode = -602
// ErrOracleRequestFinishedCode is returned if Oracle request submitted is already completely processed.
// Can be returned only by the C# RPC server.
ErrOracleRequestFinishedCode = -603
// ErrOracleRequestNotFoundCode is returned if Oracle request submitted is not known to this node.
// Can be returned only by the C# RPC server.
ErrOracleRequestNotFoundCode = -604
// ErrOracleNotDesignatedNodeCode is returned if Oracle service is enabled, but this node is not designated
// to provide this functionality. Can be returned only by the C# RPC server.
ErrOracleNotDesignatedNodeCode = -605
// ErrUnsupportedStateCode is returned if this node can't answer requests for old state because it's configured
// to keep only the latest one.
ErrUnsupportedStateCode = -606
// ErrInvalidProofCode is returned if state proof verification failed.
ErrInvalidProofCode = -607
// ErrExecutionFailedCode is returned from a call made a VM execution, but it has failed.
ErrExecutionFailedCode = -608
)
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.
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.")
// ErrValidationFailed represents SubmitError with code -504.
ErrValidationFailed = NewSubmitError(-504, "Block or transaction 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.")
// ErrInvalidParams represents a generic "Invalid params" error.
ErrInvalidParams = NewInvalidParamsError("Invalid params")
// ErrUnknownBlock represents an error with code [ErrUnknownBlockCode].
// Call that accepts as a parameter or searches for a header or a block as a part of its job can't find it.
ErrUnknownBlock = NewErrorWithCode(ErrUnknownBlockCode, "Unknown block")
// ErrUnknownContract represents an error with code [ErrUnknownContractCode].
// Call that accepts as a parameter or searches for a contract as a part of its job can't find it.
ErrUnknownContract = NewErrorWithCode(ErrUnknownContractCode, "Unknown contract")
// ErrUnknownTransaction represents an error with code [ErrUnknownTransactionCode].
// Call that accepts as a parameter or searches for a transaction as a part of its job can't find it.
ErrUnknownTransaction = NewErrorWithCode(ErrUnknownTransactionCode, "Unknown transaction")
// ErrUnknownStorageItem represents an error with code [ErrUnknownStorageItemCode].
// Call that looks for an item in the contract storage as part of its job can't find it.
ErrUnknownStorageItem = NewErrorWithCode(ErrUnknownStorageItemCode, "Unknown storage item")
// ErrUnknownScriptContainer represents an error with code [ErrUnknownScriptContainerCode].
// Call that accepts as a parameter or searches for a script container (a block or transaction)
// as a part of its job can't find it (this error generalizes [ErrUnknownBlockCode] and [ErrUnknownTransactionCode]
// in cases where it's needed).
ErrUnknownScriptContainer = NewErrorWithCode(ErrUnknownScriptContainerCode, "Unknown script container")
// ErrUnknownStateRoot represents an error with code [ErrUnknownStateRootCode].
// Call that accepts as a parameter or searches for a state root as a part of its job can't find it.
ErrUnknownStateRoot = NewErrorWithCode(ErrUnknownStateRootCode, "Unknown state root")
// ErrUnknownSession represents an error with code [ErrUnknownSessionCode].
// Call that accepts as a parameter or searches for an iterator session as a part of its job can't find it.
ErrUnknownSession = NewErrorWithCode(ErrUnknownSessionCode, "Unknown session")
// ErrUnknownIterator represents an error with code [ErrUnknownIteratorCode].
// Call that accepts as a parameter or searches for a session iterator as a part of its job can't find it.
ErrUnknownIterator = NewErrorWithCode(ErrUnknownIteratorCode, "Unknown iterator")
// ErrUnknownHeight represents an error with code [ErrUnknownHeightCode].
// Block or header height passed as parameter or calculated during call execution is not correct
// (out of the range known to the node).
ErrUnknownHeight = NewErrorWithCode(ErrUnknownHeightCode, "Unknown height")
// ErrInsufficientFundsWallet represents an error with code [ErrInsufficientFundsWalletCode]. Can be returned only by the C# RPC server.
// Transaction that sends some assets can't be created because it fails.
ErrInsufficientFundsWallet = NewErrorWithCode(ErrInsufficientFundsWalletCode, "Insufficient funds")
// ErrWalletFeeLimit represents an error with code [ErrWalletFeeLimitCode]. Can be returned only by the C# RPC server.
// Transaction requires more network fee to be paid than is allowed by settings.
ErrWalletFeeLimit = NewErrorWithCode(ErrWalletFeeLimitCode, "Fee limit exceeded")
// ErrNoOpenedWallet represents an error with code [ErrNoOpenedWalletCode]. Can be returned only by the C# RPC server.
// Server doesn't have any opened wallet to operate with.
ErrNoOpenedWallet = NewErrorWithCode(ErrNoOpenedWalletCode, "No opened wallet")
// ErrWalletNotFound represents an error with code [ErrWalletNotFoundCode]. Can be returned only by the C# RPC server.
// Specified (or configured) wallet file path is invalid.
ErrWalletNotFound = NewErrorWithCode(ErrWalletNotFoundCode, "Wallet not found")
// ErrWalletNotSupported represents an error with code [ErrWalletNotSupportedCode]. Can be returned only by the C# RPC server.
// Specified (or configured) file can't be opened as a wallet.
ErrWalletNotSupported = NewErrorWithCode(ErrWalletNotSupportedCode, "Wallet not supported")
// ErrVerificationFailed represents an error with code [ErrVerificationFailedCode].
// Any verification error that can't be expressed by other codes.
ErrVerificationFailed = NewErrorWithCode(ErrVerificationFailedCode, "Unclassified inventory verification error")
// ErrAlreadyExists represents an error with code [ErrAlreadyExistsCode].
// Block or transaction is already accepted and processed on chain.
ErrAlreadyExists = NewErrorWithCode(ErrAlreadyExistsCode, "Inventory already exists on chain")
// ErrMempoolCapReached represents an error with code [ErrMempoolCapReachedCode].
// No more transactions can be accepted into the memory pool (unless they have a priority) as its full capacity is reached.
ErrMempoolCapReached = NewErrorWithCode(ErrMempoolCapReachedCode, "The memory pool is full and no more transactions can be sent")
// ErrAlreadyInPool represents an error with code [ErrAlreadyInPoolCode].
// Transaction is already pooled, but not yet accepted into a block.
ErrAlreadyInPool = NewErrorWithCode(ErrAlreadyInPoolCode, "Transaction already exists in the memory pool")
// ErrInsufficientNetworkFee represents an error with code [ErrInsufficientNetworkFeeCode].
// Transaction has incorrect (too small per Policy setting) network fee value.
ErrInsufficientNetworkFee = NewErrorWithCode(ErrInsufficientNetworkFeeCode, "Insufficient network fee")
// ErrPolicyFailed represents an error with code [ErrPolicyFailedCode].
// Denied by the Policy contract (one of signers is blocked).
ErrPolicyFailed = NewErrorWithCode(ErrPolicyFailedCode, "One of the Policy filters failed")
// ErrInvalidScript represents an error with code [ErrInvalidScriptCode].
// Transaction contains incorrect executable script.
ErrInvalidScript = NewErrorWithCode(ErrInvalidScriptCode, "Invalid script")
// ErrInvalidAttribute represents an error with code [ErrInvalidAttributeCode].
// Transaction contains an invalid attribute.
ErrInvalidAttribute = NewErrorWithCode(ErrInvalidAttributeCode, "Invalid transaction attribute")
// ErrInvalidSignature represents an error with code [ErrInvalidSignatureCode].
// One of the verification scripts failed.
ErrInvalidSignature = NewErrorWithCode(ErrInvalidSignatureCode, "Invalid signature")
// ErrInvalidSize represents an error with code [ErrInvalidSizeCode].
// Transaction or its script is too big.
ErrInvalidSize = NewErrorWithCode(ErrInvalidSizeCode, "Invalid inventory size")
// ErrExpiredTransaction represents an error with code [ErrExpiredTransactionCode].
// Transaction's ValidUntilBlock value is already in the past.
ErrExpiredTransaction = NewErrorWithCode(ErrExpiredTransactionCode, "Expired transaction")
// ErrInsufficientFunds represents an error with code [ErrInsufficientFundsCode].
// Sender doesn't have enough GAS to pay for all currently pooled transactions.
ErrInsufficientFunds = NewErrorWithCode(ErrInsufficientFundsCode, "Insufficient funds")
// ErrInvalidVerificationFunction represents an error with code [ErrInvalidVerificationFunctionCode].
// Contract doesn't have a verify method or this method doesn't return proper value.
ErrInvalidVerificationFunction = NewErrorWithCode(ErrInvalidVerificationFunctionCode, "Invalid verification function")
// ErrSessionsDisabled represents an error with code [ErrSessionsDisabledCode].
// Iterator session support is not enabled on the server.
ErrSessionsDisabled = NewErrorWithCode(ErrSessionsDisabledCode, "Sessions disabled")
// ErrOracleDisabled represents an error with code [ErrOracleDisabledCode].
// Service is not enabled in the configuration.
ErrOracleDisabled = NewErrorWithCode(ErrOracleDisabledCode, "Oracle service is not running")
// ErrOracleRequestFinished represents an error with code [ErrOracleRequestFinishedCode]. Can be returned only by the C# RPC server.
// The oracle request submitted is already completely processed.
ErrOracleRequestFinished = NewErrorWithCode(ErrOracleRequestFinishedCode, "Oracle request has already been finished")
// ErrOracleRequestNotFound represents an error with code [ErrOracleRequestNotFoundCode]. Can be returned only by the C# RPC server.
// The oracle request submitted is not known to this node.
ErrOracleRequestNotFound = NewErrorWithCode(ErrOracleRequestNotFoundCode, "Oracle request is not found")
// ErrOracleNotDesignatedNode represents an error with code [ErrOracleNotDesignatedNodeCode]. Can be returned only by the C# RPC server.
// Oracle service is enabled, but this node is not designated to provide this functionality.
ErrOracleNotDesignatedNode = NewErrorWithCode(ErrOracleNotDesignatedNodeCode, "Not a designated oracle node")
// ErrUnsupportedState represents an error with code [ErrUnsupportedStateCode].
// This node can't answer requests for old state because it's configured to keep only the latest one.
ErrUnsupportedState = NewErrorWithCode(ErrUnsupportedStateCode, "Old state requests are not supported")
// ErrInvalidProof represents an error with code [ErrInvalidProofCode].
// State proof verification failed.
ErrInvalidProof = NewErrorWithCode(ErrInvalidProofCode, "Invalid proof")
// ErrExecutionFailed represents an error with code [ErrExecutionFailedCode].
// Call made a VM execution, but it has failed.
ErrExecutionFailed = NewErrorWithCode(ErrExecutionFailedCode, "Execution failed")
)
// NewError is an Error constructor that takes Error contents from its parameters.
@ -98,15 +294,9 @@ 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) *Error {
return NewError(RPCErrorCode, message, data)
}
// NewSubmitError creates a new error with
// NewErrorWithCode creates a new error with
// specified error code and error message.
func NewSubmitError(code int64, message string) *Error {
func NewErrorWithCode(code int64, message string) *Error {
return NewError(code, message, "")
}

View file

@ -44,7 +44,7 @@ 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.InvalidParamsCode:
httpCode = http.StatusUnprocessableEntity
case neorpc.MethodNotFoundCode:
httpCode = http.StatusMethodNotAllowed

View file

@ -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. Pay attention that orc is expected to be either
// untyped nil or non-nil structure implementing OracleHandler interface.
func New(chain Ledger, conf config.RPC, coreServer *network.Server,
@ -783,7 +779,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 {
@ -801,7 +797,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
@ -900,11 +896,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.ErrInvalidVerificationFunction, 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.ErrInvalidVerificationFunction, 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.
@ -1004,7 +1000,7 @@ func (s *Server) getNEP11Balances(ps params.Params) (any, *neorpc.Error) {
}
lastUpdated, err := s.chain.GetTokenLastUpdated(u)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get NEP-11 last updated block", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Failed to get NEP-11 last updated block: %s", err.Error()))
}
var count int
stateSyncPoint := lastUpdated[math.MinInt32]
@ -1092,7 +1088,7 @@ func (s *Server) getNEP11Properties(ps params.Params) (any, *neorpc.Error) {
}
props, err := s.invokeNEP11Properties(asset, token, nil)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get NEP-11 properties", err.Error())
return nil, neorpc.WrapErrorWithData(neorpc.ErrExecutionFailed, fmt.Sprintf("Failed to get NEP-11 properties: %s", err.Error()))
}
res := make(map[string]any)
for _, kv := range props {
@ -1129,7 +1125,7 @@ func (s *Server) getNEP17Balances(ps params.Params) (any, *neorpc.Error) {
}
lastUpdated, err := s.chain.GetTokenLastUpdated(u)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get NEP-17 last updated block", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Failed to get NEP-17 last updated block: %s", err.Error()))
}
stateSyncPoint := lastUpdated[math.MinInt32]
bw := io.NewBufBinWriter()
@ -1426,7 +1422,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 {
@ -1462,14 +1458,14 @@ func (s *Server) contractScriptHashFromParam(param *params.Param) (util.Uint160,
}
id, err := strconv.Atoi(nameOrHashOrIndex)
if err != nil {
return result, neorpc.NewRPCError("Invalid contract identifier (name/hash/index is expected)", err.Error())
return result, neorpc.NewInvalidParamsError(fmt.Sprintf("Invalid contract identifier (name/hash/index is expected) : %s", err.Error()))
}
if err := checkInt32(id); err != nil {
return result, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, err.Error())
}
result, err = s.chain.GetContractScriptHash(int32(id))
if err != nil {
return result, neorpc.NewRPCError("Unknown contract", "")
return result, neorpc.ErrUnknownContract
}
return result, nil
}
@ -1485,7 +1481,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.ErrUnsupportedState, fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState))
}
root, err := ps.Value(0).GetUint256()
if err != nil {
@ -1506,6 +1502,9 @@ func (s *Server) getProof(ps params.Params) (any, *neorpc.Error) {
skey := makeStorageKey(cs.ID, key)
proof, err := s.chain.GetStateModule().GetStateProof(root, skey)
if err != nil {
if errors.Is(err, mpt.ErrNotFound) {
return nil, neorpc.ErrUnknownStorageItem
}
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get proof: %s", err))
}
return &result.ProofWithKey{
@ -1516,7 +1515,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.ErrUnsupportedState, fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState))
}
root, err := ps.Value(0).GetUint256()
if err != nil {
@ -1549,7 +1548,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.ErrUnsupportedState, fmt.Sprintf("'getstate' is not supported for old states: %s", errKeepOnlyLatestState))
}
}
csHash, err := ps.Value(1).GetUint160FromHex()
@ -1567,7 +1566,10 @@ func (s *Server) getState(ps params.Params) (any, *neorpc.Error) {
sKey := makeStorageKey(cs.ID, key)
res, err := s.chain.GetStateModule().GetState(root, sKey)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get historical item state", err.Error())
if errors.Is(err, mpt.ErrNotFound) {
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("invalid key: %s", err.Error()))
}
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Failed to get historical item state: %s", err.Error()))
}
return res, nil
}
@ -1583,7 +1585,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.ErrUnsupportedState, fmt.Sprintf("'findstates' is not supported for old states: %s", errKeepOnlyLatestState))
}
}
csHash, err := ps.Value(1).GetUint160FromHex()
@ -1670,7 +1672,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)
@ -1720,7 +1722,7 @@ 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 {
if rErr == neorpc.ErrUnknownContract {
return nil, nil
}
if rErr != nil {
@ -1759,14 +1761,14 @@ func (s *Server) getrawtransaction(reqParams params.Params) (any, *neorpc.Error)
_header := s.chain.GetHeaderHash(height)
header, err := s.chain.GetHeader(_header)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get header for the transaction", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Failed to get header for the transaction: %s", err.Error()))
}
aers, err := s.chain.GetAppExecResults(txHash, trigger.Application)
if err != nil {
return nil, neorpc.NewRPCError("Failed to get application log for the transaction", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Failed to get application log for the transaction: %s", err.Error()))
}
if len(aers) == 0 {
return nil, neorpc.NewRPCError("Inconsistent application log", "application log for the transaction is empty")
return nil, neorpc.NewInternalServerError("Inconsistent application log: application log for the transaction is empty")
}
res.TransactionMetadata = result.TransactionMetadata{
Blockhash: header.Hash(),
@ -1802,7 +1804,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
}
@ -1815,7 +1817,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, neorpc.WrapErrorWithData(err, fmt.Sprintf("invalid block height: %s", err.Data))
}
headerHash := s.chain.GetHeaderHash(num)
@ -1843,7 +1845,7 @@ func (s *Server) getBlockHeader(reqParams params.Params) (any, *neorpc.Error) {
verbose, _ := reqParams.Value(1).GetBoolean()
h, err := s.chain.GetHeader(hash)
if err != nil {
return nil, neorpc.ErrUnknownHeader
return nil, neorpc.ErrUnknownBlock
}
if verbose {
@ -1877,7 +1879,7 @@ func (s *Server) getUnclaimedGas(ps params.Params) (any, *neorpc.Error) {
}
gas, err := s.chain.CalculateClaimable(u, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
if err != nil {
return nil, neorpc.NewRPCError("Can't calculate claimable", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't calculate claimable: %s", err.Error()))
}
return result.UnclaimedGas{
Address: u,
@ -1891,11 +1893,11 @@ func (s *Server) getCandidates(_ params.Params) (any, *neorpc.Error) {
validators, err := s.chain.GetNextBlockValidators()
if err != nil {
return nil, neorpc.NewRPCError("Can't get next block validators", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get next block validators: %s", err.Error()))
}
enrollments, err := s.chain.GetEnrollments()
if err != nil {
return nil, neorpc.NewRPCError("Can't get enrollments", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get enrollments: %s", err.Error()))
}
var res = make([]result.Candidate, 0)
for _, v := range enrollments {
@ -1914,11 +1916,11 @@ func (s *Server) getNextBlockValidators(_ params.Params) (any, *neorpc.Error) {
validators, err := s.chain.GetNextBlockValidators()
if err != nil {
return nil, neorpc.NewRPCError("Can't get next block validators", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get next block validators: %s", err.Error()))
}
enrollments, err := s.chain.GetEnrollments()
if err != nil {
return nil, neorpc.NewRPCError("Can't get enrollments", err.Error())
return nil, neorpc.NewInternalServerError(fmt.Sprintf("Can't get enrollments: %s", err.Error()))
}
var res = make([]result.Validator, 0)
for _, v := range enrollments {
@ -2003,7 +2005,7 @@ func (s *Server) getInvokeFunctionParams(reqParams params.Params) (*transaction.
}
script, err := params.CreateFunctionInvocationScript(scriptHash, method, invparams)
if err != nil {
return nil, false, neorpc.NewInternalServerError(fmt.Sprintf("can't create invocation script: %s", err))
return nil, false, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, fmt.Sprintf("can't create invocation script: %s", err))
}
tx.Script = script
return tx, verbose, nil
@ -2130,7 +2132,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.ErrUnsupportedState, fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState))
}
if len(reqParams) < 1 {
return 0, neorpc.ErrInvalidParams
@ -2185,8 +2187,15 @@ func (s *Server) prepareInvocationContext(t trigger.Type, script []byte, contrac
err = s.chain.InitVerificationContext(ic, contractScriptHash, &transaction.Witness{InvocationScript: script, VerificationScript: []byte{}})
if err != nil {
switch {
case errors.Is(err, core.ErrUnknownVerificationContract):
return nil, neorpc.WrapErrorWithData(neorpc.ErrUnknownContract, err.Error())
case errors.Is(err, core.ErrInvalidVerificationContract):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidVerificationFunction, err.Error())
default:
return nil, neorpc.NewInternalServerError(fmt.Sprintf("can't prepare verification VM: %s", err))
}
}
} else {
ic.VM.LoadScriptWithFlags(script, callflag.All)
}
@ -2319,7 +2328,7 @@ func (s *Server) registerOrDumpIterator(item stackitem.Item) (stackitem.Item, uu
func (s *Server) traverseIterator(reqParams params.Params) (any, *neorpc.Error) {
if !s.config.SessionEnabled {
return nil, neorpc.NewInvalidRequestError("sessions are disabled")
return nil, neorpc.ErrSessionsDisabled
}
sID, err := reqParams.Value(0).GetUUID()
if err != nil {
@ -2376,7 +2385,7 @@ func (s *Server) traverseIterator(reqParams params.Params) (any, *neorpc.Error)
func (s *Server) terminateSession(reqParams params.Params) (any, *neorpc.Error) {
if !s.config.SessionEnabled {
return nil, neorpc.NewInvalidRequestError("sessions are disabled")
return nil, neorpc.ErrSessionsDisabled
}
sID, err := reqParams.Value(0).GetUUID()
if err != nil {
@ -2412,24 +2421,13 @@ func (s *Server) submitBlock(reqParams params.Params) (any, *neorpc.Error) {
if r.Err != nil {
return nil, neorpc.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, neorpc.WrapErrorWithData(neorpc.ErrAlreadyExists, err.Error())
default:
return nil, neorpc.WrapErrorWithData(neorpc.ErrValidationFailed, err.Error())
}
}
return &result.RelayResult{
Hash: b.Hash(),
}, nil
return getRelayResult(s.chain.AddBlock(b), b.Hash())
}
// submitNotaryRequest broadcasts P2PNotaryRequest over the Neo network.
func (s *Server) submitNotaryRequest(ps params.Params) (any, *neorpc.Error) {
if !s.chain.P2PSigExtensionsEnabled() {
return nil, neorpc.NewRPCError("P2PSignatureExtensions are disabled", "")
return nil, neorpc.NewInternalServerError("P2PSignatureExtensions are disabled")
}
bytePayload, err := ps.Value(0).GetBytesBase64()
@ -2450,21 +2448,37 @@ func getRelayResult(err error, hash util.Uint256) (any, *neorpc.Error) {
return result.RelayResult{
Hash: hash,
}, nil
case errors.Is(err, core.ErrAlreadyExists):
case errors.Is(err, core.ErrTxExpired):
return nil, neorpc.WrapErrorWithData(neorpc.ErrExpiredTransaction, err.Error())
case errors.Is(err, core.ErrAlreadyExists) || errors.Is(err, core.ErrInvalidBlockIndex):
return nil, neorpc.WrapErrorWithData(neorpc.ErrAlreadyExists, err.Error())
case errors.Is(err, core.ErrAlreadyInPool):
return nil, neorpc.WrapErrorWithData(neorpc.ErrAlreadyInPool, err.Error())
case errors.Is(err, core.ErrOOM):
return nil, neorpc.WrapErrorWithData(neorpc.ErrOutOfMemory, err.Error())
return nil, neorpc.WrapErrorWithData(neorpc.ErrMempoolCapReached, err.Error())
case errors.Is(err, core.ErrPolicy):
return nil, neorpc.WrapErrorWithData(neorpc.ErrPolicyFail, err.Error())
return nil, neorpc.WrapErrorWithData(neorpc.ErrPolicyFailed, err.Error())
case errors.Is(err, core.ErrInvalidScript):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidScript, err.Error())
case errors.Is(err, core.ErrTxTooBig):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidSize, err.Error())
case errors.Is(err, core.ErrTxSmallNetworkFee):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInsufficientNetworkFee, err.Error())
case errors.Is(err, core.ErrInvalidAttribute):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidAttribute, err.Error())
case errors.Is(err, core.ErrInsufficientFunds):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInsufficientFunds, err.Error())
case errors.Is(err, core.ErrInvalidSignature):
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidSignature, err.Error())
default:
return nil, neorpc.WrapErrorWithData(neorpc.ErrValidationFailed, err.Error())
return nil, neorpc.WrapErrorWithData(neorpc.ErrVerificationFailed, err.Error())
}
}
func (s *Server) submitOracleResponse(ps params.Params) (any, *neorpc.Error) {
oraclePtr := s.oracle.Load()
if oraclePtr == nil {
return nil, neorpc.NewRPCError("Oracle is not enabled", "")
return nil, neorpc.ErrOracleDisabled
}
oracle := oraclePtr.(OracleHandler)
var pub *keys.PublicKey
@ -2481,15 +2495,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.ErrInvalidParams, 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.ErrInvalidParams, 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
@ -2803,7 +2817,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.ErrUnknownHeight, 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
}

File diff suppressed because it is too large Load diff