Merge pull request #2544 from nspcc-dev/rpc/remove-cause
rpc: remove Cause field from RPC error
This commit is contained in:
commit
6e475856aa
4 changed files with 242 additions and 197 deletions
|
@ -1,29 +1,49 @@
|
||||||
package response
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
// Error represents JSON-RPC 2.0 error type.
|
||||||
// Error object for outputting JSON-RPC 2.0
|
type Error struct {
|
||||||
// errors.
|
Code int64 `json:"code"`
|
||||||
Error struct {
|
Message string `json:"message"`
|
||||||
Code int64 `json:"code"`
|
Data string `json:"data,omitempty"`
|
||||||
HTTPCode int `json:"-"`
|
}
|
||||||
Cause error `json:"-"`
|
|
||||||
Message string `json:"message"`
|
// Standard RPC error codes defined by the JSON-RPC 2.0 specification.
|
||||||
Data string `json:"data,omitempty"`
|
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.
|
// RPC error codes defined by the Neo JSON-RPC specification extension.
|
||||||
const InternalServerErrorCode = -32603
|
const (
|
||||||
|
// RPCErrorCode is returned on RPC request processing error.
|
||||||
|
RPCErrorCode = -100
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrInvalidParams represents a generic 'invalid parameters' error.
|
// ErrInvalidParams represents a generic 'invalid parameters' error.
|
||||||
ErrInvalidParams = NewInvalidParamsError("", errors.New("invalid params"))
|
ErrInvalidParams = NewInvalidParamsError("invalid params")
|
||||||
|
// ErrUnknownBlock is returned if requested block is not found.
|
||||||
|
ErrUnknownBlock = NewError(RPCErrorCode, "Unknown block", "")
|
||||||
|
// ErrUnknownTransaction is returned if requested transaction is not found.
|
||||||
|
ErrUnknownTransaction = NewError(RPCErrorCode, "Unknown transaction", "")
|
||||||
|
// ErrUnknownHeader is returned when requested header is not found.
|
||||||
|
ErrUnknownHeader = NewError(RPCErrorCode, "Unknown header", "")
|
||||||
|
// ErrUnknownScriptContainer is returned when requested block or transaction is not found.
|
||||||
|
ErrUnknownScriptContainer = NewError(RPCErrorCode, "Unknown script container", "")
|
||||||
|
// ErrUnknownStateRoot is returned when requested state root is not found.
|
||||||
|
ErrUnknownStateRoot = NewError(RPCErrorCode, "Unknown state root", "")
|
||||||
// ErrAlreadyExists represents SubmitError with code -501.
|
// ErrAlreadyExists represents SubmitError with code -501.
|
||||||
ErrAlreadyExists = NewSubmitError(-501, "Block or transaction already exists and cannot be sent repeatedly.")
|
ErrAlreadyExists = NewSubmitError(-501, "Block or transaction already exists and cannot be sent repeatedly.")
|
||||||
// ErrOutOfMemory represents SubmitError with code -502.
|
// ErrOutOfMemory represents SubmitError with code -502.
|
||||||
|
@ -38,70 +58,76 @@ var (
|
||||||
ErrUnknown = NewSubmitError(-500, "Unknown error.")
|
ErrUnknown = NewSubmitError(-500, "Unknown error.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewError is an Error constructor that takes Error contents from its
|
// NewError is an Error constructor that takes Error contents from its parameters.
|
||||||
// parameters.
|
func NewError(code int64, message string, data string) *Error {
|
||||||
func NewError(code int64, httpCode int, message string, data string, cause error) *Error {
|
|
||||||
return &Error{
|
return &Error{
|
||||||
Code: code,
|
Code: code,
|
||||||
HTTPCode: httpCode,
|
Message: message,
|
||||||
Cause: cause,
|
Data: data,
|
||||||
Message: message,
|
|
||||||
Data: data,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParseError creates a new error with code
|
// NewParseError creates a new error with code
|
||||||
// -32700.
|
// -32700.
|
||||||
func NewParseError(data string, cause error) *Error {
|
func NewParseError(data string) *Error {
|
||||||
return NewError(-32700, http.StatusBadRequest, "Parse Error", data, cause)
|
return NewError(BadRequestCode, "Parse Error", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInvalidRequestError creates a new error with
|
// NewInvalidRequestError creates a new error with
|
||||||
// code -32600.
|
// code -32600.
|
||||||
func NewInvalidRequestError(data string, cause error) *Error {
|
func NewInvalidRequestError(data string) *Error {
|
||||||
return NewError(-32600, http.StatusUnprocessableEntity, "Invalid Request", data, cause)
|
return NewError(InvalidRequestCode, "Invalid Request", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMethodNotFoundError creates a new error with
|
// NewMethodNotFoundError creates a new error with
|
||||||
// code -32601.
|
// code -32601.
|
||||||
func NewMethodNotFoundError(data string, cause error) *Error {
|
func NewMethodNotFoundError(data string) *Error {
|
||||||
return NewError(-32601, http.StatusMethodNotAllowed, "Method not found", data, cause)
|
return NewError(MethodNotFoundCode, "Method not found", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInvalidParamsError creates a new error with
|
// NewInvalidParamsError creates a new error with
|
||||||
// code -32602.
|
// code -32602.
|
||||||
func NewInvalidParamsError(data string, cause error) *Error {
|
func NewInvalidParamsError(data string) *Error {
|
||||||
return NewError(-32602, http.StatusUnprocessableEntity, "Invalid Params", data, cause)
|
return NewError(InvalidParamsCode, "Invalid Params", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInternalServerError creates a new error with
|
// NewInternalServerError creates a new error with
|
||||||
// code -32603.
|
// code -32603.
|
||||||
func NewInternalServerError(data string, cause error) *Error {
|
func NewInternalServerError(data string) *Error {
|
||||||
return NewError(InternalServerErrorCode, http.StatusInternalServerError, "Internal error", data, cause)
|
return NewError(InternalServerErrorCode, "Internal error", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRPCError creates a new error with
|
// NewRPCError creates a new error with
|
||||||
// code -100.
|
// code -100.
|
||||||
func NewRPCError(message string, data string, cause error) *Error {
|
func NewRPCError(message string, data string) *Error {
|
||||||
return NewError(-100, http.StatusUnprocessableEntity, message, data, cause)
|
return NewError(RPCErrorCode, message, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubmitError creates a new error with
|
// NewSubmitError creates a new error with
|
||||||
// specified error code and error message.
|
// specified error code and error message.
|
||||||
func NewSubmitError(code int64, message string) *Error {
|
func NewSubmitError(code int64, message string) *Error {
|
||||||
return NewError(code, http.StatusUnprocessableEntity, message, "", nil)
|
return NewError(code, 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)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s (%d) - %s - %s", e.Message, e.Code, e.Data, e.Cause)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapErrorWithData returns copy of the given error with the specified data and cause.
|
// WrapErrorWithData returns copy of the given error with the specified data and cause.
|
||||||
// It does not modify the source error.
|
// It does not modify the source error.
|
||||||
func WrapErrorWithData(e *Error, data error) *Error {
|
func WrapErrorWithData(e *Error, data string) *Error {
|
||||||
return NewError(e.Code, e.HTTPCode, e.Message, data.Error(), data)
|
return NewError(e.Code, e.Message, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if len(e.Data) == 0 {
|
||||||
|
return fmt.Sprintf("%s (%d)", e.Message, e.Code)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (%d) - %s", e.Message, e.Code, e.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
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,38 +24,6 @@ type Raw struct {
|
||||||
Result json.RawMessage `json:"result,omitempty"`
|
Result json.RawMessage `json:"result,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AbstractResult is an interface which represents either single JSON-RPC 2.0 response
|
|
||||||
// or batch JSON-RPC 2.0 response.
|
|
||||||
type AbstractResult interface {
|
|
||||||
RunForErrors(f func(jsonErr *Error))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstract represents abstract JSON-RPC 2.0 response, it differs from Raw in
|
|
||||||
// that Result field is an interface here.
|
|
||||||
type Abstract struct {
|
|
||||||
HeaderAndError
|
|
||||||
Result interface{} `json:"result,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunForErrors implements AbstractResult interface.
|
|
||||||
func (a Abstract) RunForErrors(f func(jsonErr *Error)) {
|
|
||||||
if a.Error != nil {
|
|
||||||
f(a.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AbstractBatch represents abstract JSON-RPC 2.0 batch-response.
|
|
||||||
type AbstractBatch []Abstract
|
|
||||||
|
|
||||||
// RunForErrors implements AbstractResult interface.
|
|
||||||
func (ab AbstractBatch) RunForErrors(f func(jsonErr *Error)) {
|
|
||||||
for _, a := range ab {
|
|
||||||
if a.Error != nil {
|
|
||||||
f(a.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notification is a type used to represent wire format of events, they're
|
// 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
|
// special in that they look like requests but they don't have IDs and their
|
||||||
// "method" is actually an event name.
|
// "method" is actually an event name.
|
||||||
|
|
57
pkg/rpc/server/error.go
Normal file
57
pkg/rpc/server/error.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
// abstractResult is an interface which represents either single JSON-RPC 2.0 response
|
||||||
|
// or batch JSON-RPC 2.0 response.
|
||||||
|
type abstractResult interface {
|
||||||
|
RunForErrors(f func(jsonErr *response.Error))
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstract represents abstract JSON-RPC 2.0 response. It is used as a server-side response
|
||||||
|
// representation.
|
||||||
|
type abstract struct {
|
||||||
|
response.Header
|
||||||
|
Error *response.Error `json:"error,omitempty"`
|
||||||
|
Result interface{} `json:"result,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunForErrors implements abstractResult interface.
|
||||||
|
func (a abstract) RunForErrors(f func(jsonErr *response.Error)) {
|
||||||
|
if a.Error != nil {
|
||||||
|
f(a.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstractBatch represents abstract JSON-RPC 2.0 batch-response.
|
||||||
|
type abstractBatch []abstract
|
||||||
|
|
||||||
|
// RunForErrors implements abstractResult interface.
|
||||||
|
func (ab abstractBatch) RunForErrors(f func(jsonErr *response.Error)) {
|
||||||
|
for _, a := range ab {
|
||||||
|
if a.Error != nil {
|
||||||
|
f(a.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHTTPCodeForError(respErr *response.Error) int {
|
||||||
|
var httpCode int
|
||||||
|
switch respErr.Code {
|
||||||
|
case response.BadRequestCode:
|
||||||
|
httpCode = http.StatusBadRequest
|
||||||
|
case response.InvalidRequestCode, response.RPCErrorCode, response.InvalidParamsCode:
|
||||||
|
httpCode = http.StatusUnprocessableEntity
|
||||||
|
case response.MethodNotFoundCode:
|
||||||
|
httpCode = http.StatusMethodNotAllowed
|
||||||
|
case response.InternalServerErrorCode:
|
||||||
|
httpCode = http.StatusInternalServerError
|
||||||
|
default:
|
||||||
|
httpCode = http.StatusUnprocessableEntity
|
||||||
|
}
|
||||||
|
return httpCode
|
||||||
|
}
|
|
@ -159,7 +159,7 @@ var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (inter
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidBlockHeightError = func(index int, height int) *response.Error {
|
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
|
// 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(
|
s.writeHTTPErrorResponse(
|
||||||
request.NewIn(),
|
request.NewIn(),
|
||||||
w,
|
w,
|
||||||
response.NewInternalServerError("websocket users limit reached", fmt.Errorf("%d subscribers are allowed at max", maxSubscribers)),
|
response.NewInternalServerError("websocket users limit reached"),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ
|
||||||
s.log.Info("websocket connection upgrade failed", zap.Error(err))
|
s.log.Info("websocket connection upgrade failed", zap.Error(err))
|
||||||
return
|
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)
|
subChan := make(chan *websocket.PreparedMessage, notificationBufSize)
|
||||||
subscr := &subscriber{writer: subChan, ws: ws}
|
subscr := &subscriber{writer: subChan, ws: ws}
|
||||||
s.subsLock.Lock()
|
s.subsLock.Lock()
|
||||||
|
@ -325,16 +325,14 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ
|
||||||
s.writeHTTPErrorResponse(
|
s.writeHTTPErrorResponse(
|
||||||
request.NewIn(),
|
request.NewIn(),
|
||||||
w,
|
w,
|
||||||
response.NewInvalidParamsError(
|
response.NewInvalidParamsError(fmt.Sprintf("invalid method '%s', please retry with 'POST'", httpRequest.Method)),
|
||||||
fmt.Sprintf("Invalid method '%s', please retry with 'POST'", httpRequest.Method), errors.New("unsupported HTTP request method"),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := req.DecodeData(httpRequest.Body)
|
err := req.DecodeData(httpRequest.Body)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,12 +340,12 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ
|
||||||
s.writeHTTPServerResponse(req, w, resp)
|
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 {
|
if req.In != nil {
|
||||||
req.In.Method = escapeForLog(req.In.Method) // No valid method name will be changed by it.
|
req.In.Method = escapeForLog(req.In.Method) // No valid method name will be changed by it.
|
||||||
return s.handleIn(req.In, sub)
|
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 {
|
for i, in := range req.Batch {
|
||||||
in.Method = escapeForLog(in.Method) // No valid method name will be changed by it.
|
in.Method = escapeForLog(in.Method) // No valid method name will be changed by it.
|
||||||
resp[i] = s.handleIn(&in, sub)
|
resp[i] = s.handleIn(&in, sub)
|
||||||
|
@ -355,11 +353,11 @@ func (s *Server) handleRequest(req *request.Request, sub *subscriber) response.A
|
||||||
return resp
|
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 res interface{}
|
||||||
var resErr *response.Error
|
var resErr *response.Error
|
||||||
if req.JSONRPC != request.JSONRPCVersion {
|
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)
|
reqParams := request.Params(req.RawParams)
|
||||||
|
@ -370,7 +368,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract {
|
||||||
|
|
||||||
incCounter(req.Method)
|
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]
|
handler, ok := rpcHandlers[req.Method]
|
||||||
if ok {
|
if ok {
|
||||||
res, resErr = handler(s, reqParams)
|
res, resErr = handler(s, reqParams)
|
||||||
|
@ -383,7 +381,7 @@ func (s *Server) handleIn(req *request.In, sub *subscriber) response.Abstract {
|
||||||
return s.packResponse(req, res, resErr)
|
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)
|
pingTicker := time.NewTicker(wsPingPeriod)
|
||||||
eventloop:
|
eventloop:
|
||||||
for {
|
for {
|
||||||
|
@ -436,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)
|
ws.SetReadLimit(s.wsReadLimit)
|
||||||
err := ws.SetReadDeadline(time.Now().Add(wsPongLimit))
|
err := ws.SetReadDeadline(time.Now().Add(wsPongLimit))
|
||||||
ws.SetPongHandler(func(string) error { return ws.SetReadDeadline(time.Now().Add(wsPongLimit)) })
|
ws.SetPongHandler(func(string) error { return ws.SetReadDeadline(time.Now().Add(wsPongLimit)) })
|
||||||
|
@ -513,7 +511,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro
|
||||||
|
|
||||||
block, err := s.chain.GetBlock(hash)
|
block, err := s.chain.GetBlock(hash)
|
||||||
if err != nil {
|
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 {
|
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) {
|
func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) {
|
||||||
port, err := s.coreServer.Port()
|
port, err := s.coreServer.Port()
|
||||||
if err != nil {
|
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()
|
cfg := s.chain.GetConfig()
|
||||||
|
@ -605,15 +603,15 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re
|
||||||
}
|
}
|
||||||
byteTx, err := reqParams[0].GetBytesBase64()
|
byteTx, err := reqParams[0].GetBytesBase64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error())
|
||||||
}
|
}
|
||||||
tx, err := transaction.NewTransactionFromBytes(byteTx)
|
tx, err := transaction.NewTransactionFromBytes(byteTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error())
|
||||||
}
|
}
|
||||||
hashablePart, err := tx.EncodeHashableFields()
|
hashablePart, err := tx.EncodeHashableFields()
|
||||||
if err != nil {
|
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))
|
size := len(hashablePart) + io.GetVarSize(len(tx.Signers))
|
||||||
var (
|
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
|
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))
|
gasConsumed, err := s.chain.VerifyWitness(signer.Account, tx, &tx.Scripts[i], int64(s.config.MaxGasInvoke))
|
||||||
if err != nil {
|
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
|
netFee += gasConsumed
|
||||||
size += io.GetVarSize([]byte{}) + // verification script is empty (contract-based witness)
|
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)
|
appExecResults, err := s.chain.GetAppExecResults(hash, trigger.All)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewRPCError("Unknown transaction or block", "", err)
|
return nil, response.WrapErrorWithData(response.ErrUnknownScriptContainer, fmt.Sprintf("failed to locate application log: %s", err))
|
||||||
}
|
}
|
||||||
return result.NewApplicationLog(hash, appExecResults, trig), nil
|
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)
|
lastUpdated, err := s.chain.GetTokenLastUpdated(u)
|
||||||
if err != nil {
|
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
|
var count int
|
||||||
stateSyncPoint := lastUpdated[math.MinInt32]
|
stateSyncPoint := lastUpdated[math.MinInt32]
|
||||||
|
@ -726,7 +724,7 @@ contract_loop:
|
||||||
if !ok {
|
if !ok {
|
||||||
cfg := s.chain.GetConfig()
|
cfg := s.chain.GetConfig()
|
||||||
if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks {
|
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
|
lub = stateSyncPoint
|
||||||
}
|
}
|
||||||
|
@ -788,7 +786,7 @@ func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.E
|
||||||
}
|
}
|
||||||
props, err := s.invokeNEP11Properties(asset, token, nil)
|
props, err := s.invokeNEP11Properties(asset, token, nil)
|
||||||
if err != 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{})
|
res := make(map[string]interface{})
|
||||||
for _, kv := range props {
|
for _, kv := range props {
|
||||||
|
@ -825,7 +823,7 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err
|
||||||
}
|
}
|
||||||
lastUpdated, err := s.chain.GetTokenLastUpdated(u)
|
lastUpdated, err := s.chain.GetTokenLastUpdated(u)
|
||||||
if err != nil {
|
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]
|
stateSyncPoint := lastUpdated[math.MinInt32]
|
||||||
bw := io.NewBufBinWriter()
|
bw := io.NewBufBinWriter()
|
||||||
|
@ -845,7 +843,7 @@ func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Err
|
||||||
if !ok {
|
if !ok {
|
||||||
cfg := s.chain.GetConfig()
|
cfg := s.chain.GetConfig()
|
||||||
if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks {
|
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
|
lub = stateSyncPoint
|
||||||
}
|
}
|
||||||
|
@ -977,7 +975,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}
|
||||||
|
|
||||||
start, end, limit, page, err := getTimestampsAndLimit(ps, 1)
|
start, end, limit, page, err := getTimestampsAndLimit(ps, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInvalidParamsError(err.Error(), err)
|
return nil, response.NewInvalidParamsError(fmt.Sprintf("malformed timestamps/limit: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
bs := &tokenTransfers{
|
bs := &tokenTransfers{
|
||||||
|
@ -1068,7 +1066,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if err != nil {
|
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
|
return bs, nil
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +1101,7 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err
|
||||||
return 0, response.ErrInvalidParams
|
return 0, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
if err := checkInt32(id); err != nil {
|
if err := checkInt32(id); err != nil {
|
||||||
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return 0, response.WrapErrorWithData(response.ErrInvalidParams, err.Error())
|
||||||
}
|
}
|
||||||
result = int32(id)
|
result = int32(id)
|
||||||
}
|
}
|
||||||
|
@ -1130,14 +1128,14 @@ func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160
|
||||||
}
|
}
|
||||||
id, err := strconv.Atoi(nameOrHashOrIndex)
|
id, err := strconv.Atoi(nameOrHashOrIndex)
|
||||||
if err != nil {
|
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 {
|
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))
|
result, err = s.chain.GetContractScriptHash(int32(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, response.NewRPCError("Unknown contract", "", err)
|
return result, response.NewRPCError("Unknown contract", "")
|
||||||
}
|
}
|
||||||
return result, nil
|
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) {
|
func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) {
|
||||||
if s.chain.GetConfig().KeepOnlyLatestState {
|
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()
|
root, err := ps.Value(0).GetUint256()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1174,7 +1172,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) {
|
||||||
skey := makeStorageKey(cs.ID, key)
|
skey := makeStorageKey(cs.ID, key)
|
||||||
proof, err := s.chain.GetStateModule().GetStateProof(root, skey)
|
proof, err := s.chain.GetStateModule().GetStateProof(root, skey)
|
||||||
if err != nil {
|
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{
|
return &result.ProofWithKey{
|
||||||
Key: skey,
|
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) {
|
func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) {
|
||||||
if s.chain.GetConfig().KeepOnlyLatestState {
|
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()
|
root, err := ps.Value(0).GetUint256()
|
||||||
if err != nil {
|
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) {
|
func (s *Server) getState(ps request.Params) (interface{}, *response.Error) {
|
||||||
root, err := ps.Value(0).GetUint256()
|
root, err := ps.Value(0).GetUint256()
|
||||||
if err != nil {
|
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 {
|
if s.chain.GetConfig().KeepOnlyLatestState {
|
||||||
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
|
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
|
||||||
if err != nil {
|
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) {
|
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()
|
csHash, err := ps.Value(1).GetUint160FromHex()
|
||||||
if err != nil {
|
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()
|
key, err := ps.Value(2).GetBytesBase64()
|
||||||
if err != nil {
|
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)
|
cs, respErr := s.getHistoricalContractState(root, csHash)
|
||||||
if respErr != nil {
|
if respErr != nil {
|
||||||
|
@ -1235,7 +1233,7 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.Error) {
|
||||||
sKey := makeStorageKey(cs.ID, key)
|
sKey := makeStorageKey(cs.ID, key)
|
||||||
res, err := s.chain.GetStateModule().GetState(root, sKey)
|
res, err := s.chain.GetStateModule().GetState(root, sKey)
|
||||||
if err != nil {
|
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
|
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) {
|
func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) {
|
||||||
root, err := ps.Value(0).GetUint256()
|
root, err := ps.Value(0).GetUint256()
|
||||||
if err != nil {
|
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 {
|
if s.chain.GetConfig().KeepOnlyLatestState {
|
||||||
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
|
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
|
||||||
if err != nil {
|
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) {
|
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()
|
csHash, err := ps.Value(1).GetUint160FromHex()
|
||||||
if err != nil {
|
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()
|
prefix, err := ps.Value(2).GetBytesBase64()
|
||||||
if err != nil {
|
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 (
|
var (
|
||||||
key []byte
|
key []byte
|
||||||
|
@ -1269,11 +1267,11 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) {
|
||||||
if len(ps) > 3 {
|
if len(ps) > 3 {
|
||||||
key, err = ps.Value(3).GetBytesBase64()
|
key, err = ps.Value(3).GetBytesBase64()
|
||||||
if err != nil {
|
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 len(key) > 0 {
|
||||||
if !bytes.HasPrefix(key, prefix) {
|
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):]
|
key = key[len(prefix):]
|
||||||
} else {
|
} else {
|
||||||
|
@ -1284,7 +1282,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) {
|
||||||
if len(ps) > 4 {
|
if len(ps) > 4 {
|
||||||
count, err = ps.Value(4).GetInt()
|
count, err = ps.Value(4).GetInt()
|
||||||
if err != nil {
|
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 {
|
if count > s.config.MaxFindResultItems {
|
||||||
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)
|
pKey := makeStorageKey(cs.ID, prefix)
|
||||||
kvs, err := s.chain.GetStateModule().FindStates(root, pKey, key, count+1) // +1 to define result truncation
|
kvs, err := s.chain.GetStateModule().FindStates(root, pKey, key, count+1) // +1 to define result truncation
|
||||||
if err != nil {
|
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{}
|
res := result.FindStates{}
|
||||||
if len(kvs) == count+1 {
|
if len(kvs) == count+1 {
|
||||||
|
@ -1307,7 +1305,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) {
|
||||||
if len(kvs) > 0 {
|
if len(kvs) > 0 {
|
||||||
proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[0].Key)
|
proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[0].Key)
|
||||||
if err != nil {
|
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{
|
res.FirstProof = &result.ProofWithKey{
|
||||||
Key: kvs[0].Key,
|
Key: kvs[0].Key,
|
||||||
|
@ -1317,7 +1315,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) {
|
||||||
if len(kvs) > 1 {
|
if len(kvs) > 1 {
|
||||||
proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[len(kvs)-1].Key)
|
proof, err := s.chain.GetStateModule().GetStateProof(root, kvs[len(kvs)-1].Key)
|
||||||
if err != nil {
|
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{
|
res.LastProof = &result.ProofWithKey{
|
||||||
Key: kvs[len(kvs)-1].Key,
|
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))
|
csKey := makeStorageKey(native.ManagementContractID, native.MakeContractKey(csHash))
|
||||||
csBytes, err := s.chain.GetStateModule().GetState(root, csKey)
|
csBytes, err := s.chain.GetStateModule().GetState(root, csKey)
|
||||||
if err != nil {
|
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)
|
contract := new(state.Contract)
|
||||||
err = stackitem.DeserializeConvertible(csBytes, contract)
|
err = stackitem.DeserializeConvertible(csBytes, contract)
|
||||||
if err != nil {
|
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
|
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) {
|
func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) {
|
||||||
p := ps.Value(0)
|
p := ps.Value(0)
|
||||||
if p == nil {
|
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 rt *state.MPTRoot
|
||||||
var h util.Uint256
|
var h util.Uint256
|
||||||
height, err := p.GetIntStrict()
|
height, err := p.GetIntStrict()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := checkUint32(height); 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))
|
rt, err = s.chain.GetStateModule().GetStateRoot(uint32(height))
|
||||||
} else if h, err = p.GetUint256(); err == nil {
|
} 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 {
|
if err != nil {
|
||||||
return nil, response.NewRPCError("Unknown state root.", "", err)
|
return nil, response.ErrUnknownStateRoot
|
||||||
}
|
}
|
||||||
return rt, nil
|
return rt, nil
|
||||||
}
|
}
|
||||||
|
@ -1415,8 +1413,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp
|
||||||
}
|
}
|
||||||
tx, height, err := s.chain.GetTransaction(txHash)
|
tx, height, err := s.chain.GetTransaction(txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid transaction %s: %w", txHash, err)
|
return nil, response.ErrUnknownTransaction
|
||||||
return nil, response.NewRPCError("Unknown transaction", err.Error(), err)
|
|
||||||
}
|
}
|
||||||
if v, _ := reqParams.Value(1).GetBoolean(); v {
|
if v, _ := reqParams.Value(1).GetBoolean(); v {
|
||||||
if height == math.MaxUint32 {
|
if height == math.MaxUint32 {
|
||||||
|
@ -1425,14 +1422,14 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp
|
||||||
_header := s.chain.GetHeaderHash(int(height))
|
_header := s.chain.GetHeaderHash(int(height))
|
||||||
header, err := s.chain.GetHeader(_header)
|
header, err := s.chain.GetHeader(_header)
|
||||||
if err != nil {
|
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)
|
aers, err := s.chain.GetAppExecResults(txHash, trigger.Application)
|
||||||
if err != nil {
|
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 {
|
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
|
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)
|
_, height, err := s.chain.GetTransaction(h)
|
||||||
if err != nil || height == math.MaxUint32 {
|
if err != nil || height == math.MaxUint32 {
|
||||||
return nil, response.NewRPCError("Unknown transaction", "", errors.New("transaction not found"))
|
return nil, response.ErrUnknownTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
return height, nil
|
return height, nil
|
||||||
|
@ -1462,7 +1459,7 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, *respo
|
||||||
}
|
}
|
||||||
cs := s.chain.GetContractState(scriptHash)
|
cs := s.chain.GetContractState(scriptHash)
|
||||||
if cs == nil {
|
if cs == nil {
|
||||||
return nil, response.NewRPCError("Unknown contract", "", errors.New("contract not found"))
|
return nil, response.NewRPCError("Unknown contract", "")
|
||||||
}
|
}
|
||||||
return cs, nil
|
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) {
|
func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
num, err := s.blockHeightFromParam(reqParams.Value(0))
|
num, err := s.blockHeightFromParam(reqParams.Value(0))
|
||||||
if err != nil {
|
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)
|
headerHash := s.chain.GetHeaderHash(num)
|
||||||
block, errBlock := s.chain.GetBlock(headerHash)
|
block, errBlock := s.chain.GetBlock(headerHash)
|
||||||
if errBlock != nil {
|
if errBlock != nil {
|
||||||
return 0, response.NewRPCError(errBlock.Error(), "", errors.New("unknown block"))
|
return 0, response.ErrUnknownBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
var blockSysFee int64
|
var blockSysFee int64
|
||||||
|
@ -1503,7 +1500,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons
|
||||||
verbose, _ := reqParams.Value(1).GetBoolean()
|
verbose, _ := reqParams.Value(1).GetBoolean()
|
||||||
h, err := s.chain.GetHeader(hash)
|
h, err := s.chain.GetHeader(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewRPCError("unknown block", "", errors.New("unknown header"))
|
return nil, response.ErrUnknownHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
|
@ -1513,7 +1510,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
h.EncodeBinary(buf.BinWriter)
|
h.EncodeBinary(buf.BinWriter)
|
||||||
if buf.Err != nil {
|
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
|
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.
|
gas, err := s.chain.CalculateClaimable(u, s.chain.BlockHeight()+1) // +1 as in C#, for the next block.
|
||||||
if err != nil {
|
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{
|
return result.UnclaimedGas{
|
||||||
Address: u,
|
Address: u,
|
||||||
|
@ -1547,11 +1544,11 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons
|
||||||
|
|
||||||
validators, err := s.chain.GetNextBlockValidators()
|
validators, err := s.chain.GetNextBlockValidators()
|
||||||
if err != nil {
|
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()
|
enrollments, err := s.chain.GetEnrollments()
|
||||||
if err != nil {
|
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)
|
var res = make([]result.Validator, 0)
|
||||||
for _, v := range enrollments {
|
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) {
|
func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) {
|
||||||
keys, err := s.chain.GetCommittee()
|
keys, err := s.chain.GetCommittee()
|
||||||
if err != nil {
|
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
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
@ -1634,7 +1631,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction
|
||||||
}
|
}
|
||||||
script, err := request.CreateFunctionInvocationScript(scriptHash, method, params)
|
script, err := request.CreateFunctionInvocationScript(scriptHash, method, params)
|
||||||
if err != nil {
|
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
|
tx.Script = script
|
||||||
return tx, verbose, nil
|
return tx, verbose, nil
|
||||||
|
@ -1675,7 +1672,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T
|
||||||
if len(reqParams) > 1 {
|
if len(reqParams) > 1 {
|
||||||
signers, witnesses, err := reqParams[1].GetSignersWithWitnesses()
|
signers, witnesses, err := reqParams[1].GetSignersWithWitnesses()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err)
|
return nil, false, response.WrapErrorWithData(response.ErrInvalidParams, err.Error())
|
||||||
}
|
}
|
||||||
tx.Signers = signers
|
tx.Signers = signers
|
||||||
tx.Scripts = witnesses
|
tx.Scripts = witnesses
|
||||||
|
@ -1684,7 +1681,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T
|
||||||
if len(reqParams) > 2 {
|
if len(reqParams) > 2 {
|
||||||
verbose, err = reqParams[2].GetBoolean()
|
verbose, err = reqParams[2].GetBoolean()
|
||||||
if err != nil {
|
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 {
|
if len(tx.Signers) == 0 {
|
||||||
|
@ -1729,12 +1726,12 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U
|
||||||
if len(reqParams) > 1 {
|
if len(reqParams) > 1 {
|
||||||
args, err := reqParams[1].GetArray() // second `invokecontractverify` parameter is an array of arguments for `verify` method
|
args, err := reqParams[1].GetArray() // second `invokecontractverify` parameter is an array of arguments for `verify` method
|
||||||
if err != nil {
|
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 {
|
if len(args) > 0 {
|
||||||
err := request.ExpandArrayIntoScript(bw.BinWriter, args)
|
err := request.ExpandArrayIntoScript(bw.BinWriter, args)
|
||||||
if err != nil {
|
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.
|
// handling consistency.
|
||||||
func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) {
|
func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) {
|
||||||
if s.chain.GetConfig().KeepOnlyLatestState {
|
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 {
|
if len(reqParams) < 1 {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
|
@ -1770,13 +1767,13 @@ func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *res
|
||||||
if respErr != nil {
|
if respErr != nil {
|
||||||
hash, err := reqParams.Value(0).GetUint256()
|
hash, err := reqParams.Value(0).GetUint256()
|
||||||
if err != nil {
|
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)
|
b, err := s.chain.GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stateH, err := s.chain.GetStateModule().GetLatestStateHeight(hash)
|
stateH, err := s.chain.GetStateModule().GetLatestStateHeight(hash)
|
||||||
if err != nil {
|
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)
|
height = int(stateH)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1785,7 +1782,7 @@ func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *res
|
||||||
}
|
}
|
||||||
b, err := s.getFakeNextBlock(uint32(height))
|
b, err := s.getFakeNextBlock(uint32(height))
|
||||||
if err != nil {
|
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
|
return b, nil
|
||||||
}
|
}
|
||||||
|
@ -1817,13 +1814,13 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash
|
||||||
if b == nil {
|
if b == nil {
|
||||||
b, err = s.getFakeNextBlock(s.chain.BlockHeight() + 1)
|
b, err = s.getFakeNextBlock(s.chain.BlockHeight() + 1)
|
||||||
if err != nil {
|
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)
|
ic = s.chain.GetTestVM(t, tx, b)
|
||||||
} else {
|
} else {
|
||||||
ic, err = s.chain.GetTestHistoricVM(t, tx, b)
|
ic, err = s.chain.GetTestHistoricVM(t, tx, b)
|
||||||
if err != nil {
|
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 {
|
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{}})
|
err = s.chain.InitVerificationContext(ic, contractScriptHash, &transaction.Witness{InvocationScript: script, VerificationScript: []byte{}})
|
||||||
if err != nil {
|
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 {
|
} else {
|
||||||
ic.VM.LoadScriptWithFlags(script, callflag.All)
|
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) {
|
func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
blockBytes, err := reqParams.Value(0).GetBytesBase64()
|
blockBytes, err := reqParams.Value(0).GetBytesBase64()
|
||||||
if err != nil {
|
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)
|
b := block.New(s.stateRootEnabled)
|
||||||
r := io.NewBinReaderFromBuf(blockBytes)
|
r := io.NewBinReaderFromBuf(blockBytes)
|
||||||
b.DecodeBinary(r)
|
b.DecodeBinary(r)
|
||||||
if r.Err != nil {
|
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)
|
err = s.chain.AddBlock(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, core.ErrInvalidBlockIndex) || errors.Is(err, core.ErrAlreadyExists):
|
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:
|
default:
|
||||||
return nil, response.WrapErrorWithData(response.ErrValidationFailed, err)
|
return nil, response.WrapErrorWithData(response.ErrValidationFailed, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &result.RelayResult{
|
return &result.RelayResult{
|
||||||
|
@ -1882,16 +1879,16 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.E
|
||||||
// submitNotaryRequest broadcasts P2PNotaryRequest over the NEO network.
|
// 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.Error) {
|
||||||
if !s.chain.P2PSigExtensionsEnabled() {
|
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()
|
bytePayload, err := ps.Value(0).GetBytesBase64()
|
||||||
if err != nil {
|
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)
|
r, err := payload.NewP2PNotaryRequestFromBytes(bytePayload)
|
||||||
if err != nil {
|
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())
|
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,
|
Hash: hash,
|
||||||
}, nil
|
}, nil
|
||||||
case errors.Is(err, core.ErrAlreadyExists):
|
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):
|
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):
|
case errors.Is(err, core.ErrPolicy):
|
||||||
return nil, response.WrapErrorWithData(response.ErrPolicyFail, err)
|
return nil, response.WrapErrorWithData(response.ErrPolicyFail, err.Error())
|
||||||
default:
|
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) {
|
func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.Error) {
|
||||||
if s.oracle == nil {
|
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
|
var pub *keys.PublicKey
|
||||||
pubBytes, err := ps.Value(0).GetBytesBase64()
|
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())
|
pub, err = keys.NewPublicKeyFromBytes(pubBytes, elliptic.P256())
|
||||||
}
|
}
|
||||||
if err != nil {
|
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()
|
reqID, err := ps.Value(1).GetInt()
|
||||||
if err != nil {
|
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()
|
txSig, err := ps.Value(2).GetBytesBase64()
|
||||||
if err != nil {
|
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()
|
msgSig, err := ps.Value(3).GetBytesBase64()
|
||||||
if err != nil {
|
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)
|
data := broadcaster.GetMessage(pubBytes, uint64(reqID), txSig)
|
||||||
if !pub.Verify(msgSig, hash.Sha256(data).BytesBE()) {
|
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)
|
s.oracle.AddResponse(pub, uint64(reqID), txSig)
|
||||||
return json.RawMessage([]byte("{}")), nil
|
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) {
|
func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) {
|
||||||
if len(reqParams) < 1 {
|
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()
|
byteTx, err := reqParams[0].GetBytesBase64()
|
||||||
if err != nil {
|
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)
|
tx, err := transaction.NewTransactionFromBytes(byteTx)
|
||||||
if err != nil {
|
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())
|
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
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
if event == response.NotaryRequestEventID && !s.chain.P2PSigExtensionsEnabled() {
|
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.
|
// Optional filter.
|
||||||
var filter interface{}
|
var filter interface{}
|
||||||
|
@ -2011,8 +2008,7 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface
|
||||||
defer s.subsLock.Unlock()
|
defer s.subsLock.Unlock()
|
||||||
select {
|
select {
|
||||||
case <-s.shutdown:
|
case <-s.shutdown:
|
||||||
err = errors.New("server is shutting down")
|
return nil, response.NewInternalServerError("server is shutting down")
|
||||||
return nil, response.NewInternalServerError(err.Error(), err)
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
var id int
|
var id int
|
||||||
|
@ -2022,7 +2018,7 @@ func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if id == len(sub.feeds) {
|
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].event = event
|
||||||
sub.feeds[id].filter = filter
|
sub.feeds[id].filter = filter
|
||||||
|
@ -2246,13 +2242,11 @@ func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Erro
|
||||||
return num, nil
|
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.Error) abstract {
|
||||||
resp := response.Abstract{
|
resp := abstract{
|
||||||
HeaderAndError: response.HeaderAndError{
|
Header: response.Header{
|
||||||
Header: response.Header{
|
JSONRPC: r.JSONRPC,
|
||||||
JSONRPC: r.JSONRPC,
|
ID: r.RawID,
|
||||||
ID: r.RawID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if respErr != nil {
|
if respErr != nil {
|
||||||
|
@ -2266,7 +2260,7 @@ func (s *Server) packResponse(r *request.In, result interface{}, respErr *respon
|
||||||
// logRequestError is a request error logger.
|
// logRequestError is a request error logger.
|
||||||
func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) {
|
func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) {
|
||||||
logFields := []zap.Field{
|
logFields := []zap.Field{
|
||||||
zap.Error(jsonErr.Cause),
|
zap.String("cause", jsonErr.Data),
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.In != nil {
|
if r.In != nil {
|
||||||
|
@ -2290,15 +2284,15 @@ func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, js
|
||||||
s.writeHTTPServerResponse(&request.Request{In: r}, w, resp)
|
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.
|
// Errors can happen in many places and we can only catch ALL of them here.
|
||||||
resp.RunForErrors(func(jsonErr *response.Error) {
|
resp.RunForErrors(func(jsonErr *response.Error) {
|
||||||
s.logRequestError(r, jsonErr)
|
s.logRequestError(r, jsonErr)
|
||||||
})
|
})
|
||||||
if r.In != nil {
|
if r.In != nil {
|
||||||
resp := resp.(response.Abstract)
|
resp := resp.(abstract)
|
||||||
if resp.Error != nil {
|
if resp.Error != nil {
|
||||||
w.WriteHeader(resp.Error.HTTPCode)
|
w.WriteHeader(getHTTPCodeForError(resp.Error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
Loading…
Reference in a new issue