Skip to content

Commit

Permalink
Refactor to allow methods to return error codes
Browse files Browse the repository at this point in the history
  • Loading branch information
ripply committed Sep 17, 2021
1 parent 98909be commit a746d4e
Show file tree
Hide file tree
Showing 56 changed files with 444 additions and 339 deletions.
4 changes: 2 additions & 2 deletions pkg/conversion/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ func ConvertLogTopicsToStringArray(topics []interface{}) []string {
return requestedTopics
}

func SearchLogsAndFilterExtraTopics(q *qtum.Qtum, req *qtum.SearchLogsRequest) (qtum.SearchLogsResponse, error) {
func SearchLogsAndFilterExtraTopics(q *qtum.Qtum, req *qtum.SearchLogsRequest) (qtum.SearchLogsResponse, eth.JSONRPCError) {
receipts, err := q.SearchLogs(req)
if err != nil {
return nil, err
return nil, eth.NewCallbackError(err.Error())
}

hasTopics := len(req.Topics) != 0
Expand Down
90 changes: 90 additions & 0 deletions pkg/eth/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package eth

import (
"encoding/json"
"fmt"
)

// unknown service
// return fmt.Sprintf("The method %s%s%s does not exist/is not available", e.service, serviceMethodSeparator, e.method)
var MethodNotFoundErrorCode = -32601

// invalid request
var InvalidRequestErrorCode = -32600
var InvalidMessageErrorCode = -32700
var InvalidParamsErrorCode = -32602

// logic error
var CallbackErrorCode = -32000

// shutdown error
// "server is shutting down"
var ShutdownErrorCode = -32000
var ShutdownError = NewJSONRPCError(ShutdownErrorCode, "server is shutting down", nil)

func NewMethodNotFoundError(method string) JSONRPCError {
return NewJSONRPCError(
MethodNotFoundErrorCode,
fmt.Sprintf("The method %s does not exist/is not available", method),
nil,
)
}

func NewInvalidRequestError(message string) JSONRPCError {
return NewJSONRPCError(InvalidRequestErrorCode, message, nil)
}

func NewInvalidMessageError(message string) JSONRPCError {
return NewJSONRPCError(InvalidMessageErrorCode, message, nil)
}

func NewInvalidParamsError(message string) JSONRPCError {
return NewJSONRPCError(InvalidParamsErrorCode, message, nil)
}

func NewCallbackError(message string) JSONRPCError {
return NewJSONRPCError(CallbackErrorCode, message, nil)
}

type JSONRPCError interface {
Code() int
Message() string
Error() error
}

func NewJSONRPCError(code int, message string, err error) JSONRPCError {
return &GenericJSONRPCError{
code: code,
message: message,
err: err,
}
}

// JSONRPCError contains the message and code for an ETH RPC error
type GenericJSONRPCError struct {
code int
message string
err error
}

func (err *GenericJSONRPCError) Code() int {
return err.code
}

func (err *GenericJSONRPCError) Message() string {
return err.message
}

func (err *GenericJSONRPCError) Error() error {
return err.err
}

func (err *GenericJSONRPCError) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Code int `json:"code"`
Message string `json:"message"`
}{
Code: err.code,
Message: err.message,
})
}
13 changes: 1 addition & 12 deletions pkg/eth/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package eth

import (
"encoding/json"
"fmt"
)

var EmptyLogsBloom = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Expand All @@ -22,20 +21,10 @@ type JSONRPCRequest struct {
type JSONRPCResult struct {
JSONRPC string `json:"jsonrpc"`
RawResult json.RawMessage `json:"result,omitempty"`
Error *JSONRPCError `json:"error,omitempty"`
Error JSONRPCError `json:"error,omitempty"`
ID json.RawMessage `json:"id"`
}

// JSONRPCError contains the message and code for an ETH RPC error
type JSONRPCError struct {
Code int `json:"code"`
Message string `json:"message"`
}

func (err *JSONRPCError) Error() string {
return fmt.Sprintf("eth [code: %d] %s", err.Code, err.Message)
}

func NewJSONRPCResult(id json.RawMessage, res interface{}) (*JSONRPCResult, error) {
rawResult, err := json.Marshal(res)
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions pkg/internal/tests_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ type Doer interface {
AddRawResponse(requestType string, rawResponse []byte)
AddResponse(requestType string, responseResult interface{}) error
AddResponseWithRequestID(requestID int, requestType string, responseResult interface{}) error
AddError(requestType string, responseError *eth.JSONRPCError) error
AddErrorWithRequestID(requestID int, requestType string, responseError *eth.JSONRPCError) error
AddError(requestType string, responseError eth.JSONRPCError) error
AddErrorWithRequestID(requestID int, requestType string, responseError eth.JSONRPCError) error
}

func NewDoerMappedMock() *doerMappedMock {
Expand Down Expand Up @@ -90,7 +90,7 @@ func PrepareEthRPCRequest(id int, params []json.RawMessage) (*eth.JSONRPCRequest
return &requestRPC, nil
}

func prepareRawResponse(requestID int, responseResult interface{}, responseError *eth.JSONRPCError) ([]byte, error) {
func prepareRawResponse(requestID int, responseResult interface{}, responseError eth.JSONRPCError) ([]byte, error) {
requestIDRaw, err := json.Marshal(requestID)
if err != nil {
return nil, err
Expand Down Expand Up @@ -176,7 +176,7 @@ func (d *doerMappedMock) AddResponseWithRequestID(requestID int, requestType str
return nil
}

func (d *doerMappedMock) AddError(requestType string, responseError *eth.JSONRPCError) error {
func (d *doerMappedMock) AddError(requestType string, responseError eth.JSONRPCError) error {
d.mutex.Lock()
defer d.mutex.Unlock()
requestID := d.latestId + 1
Expand All @@ -190,7 +190,7 @@ func (d *doerMappedMock) AddError(requestType string, responseError *eth.JSONRPC
return nil
}

func (d *doerMappedMock) AddErrorWithRequestID(requestID int, requestType string, responseError *eth.JSONRPCError) error {
func (d *doerMappedMock) AddErrorWithRequestID(requestID int, requestType string, responseError eth.JSONRPCError) error {
d.mutex.Lock()
defer d.mutex.Unlock()
responseRaw, err := prepareRawResponse(requestID, nil, responseError)
Expand Down
8 changes: 4 additions & 4 deletions pkg/notifier/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var agentConfigNewHeadsInterval = 10 * time.Second

// Allows dependency injection of eth rpc calls as the transformer package imports this package
type Transformer interface {
Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, error)
Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError)
}

func NewAgent(ctx context.Context, qtum *qtum.Qtum, transformer Transformer) *Agent {
Expand Down Expand Up @@ -348,13 +348,13 @@ func (a *Agent) run() {
if err != nil {
panic(fmt.Sprintf("Failed to serialize eth_getBlockByHash request parameters: %s", err))
}
result, err := transformer.Transform(&eth.JSONRPCRequest{
result, jsonErr := transformer.Transform(&eth.JSONRPCRequest{
JSONRPC: "2.0",
Method: "eth_getBlockByHash",
Params: params,
}, nil)
if err != nil {
a.qtum.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash, "err", err)
if jsonErr != nil {
a.qtum.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash, "err", jsonErr)
} else {
getBlockByHashResponse, ok := result.(*eth.GetBlockByHashResponse)
if !ok {
Expand Down
11 changes: 11 additions & 0 deletions pkg/qtum/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var maximumBackoff = (2 * time.Second).Milliseconds()

type Client struct {
URL string
url *url.URL
doer doer

// hex addresses to return for eth_accounts
Expand Down Expand Up @@ -66,10 +67,16 @@ func NewClient(isMain bool, rpcURL string, opts ...func(*Client) error) (*Client
return nil, err
}

url, err := url.Parse(rpcURL)
if err != nil {
return nil, errors.Wrap(err, "Failed to parse rpc url")
}

c := &Client{
isMain: isMain,
doer: http.DefaultClient,
URL: rpcURL,
url: url,
logger: log.NewNopLogger(),
debug: false,
id: big.NewInt(0),
Expand All @@ -87,6 +94,10 @@ func NewClient(isMain bool, rpcURL string, opts ...func(*Client) error) (*Client
return c, nil
}

func (c *Client) GetURL() *url.URL {
return c.url
}

func (c *Client) IsMain() bool {
return c.isMain
}
Expand Down
7 changes: 2 additions & 5 deletions pkg/qtum/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,13 @@ func GetErrorCode(err error) int {
return errorCode
}

func GetErrorResponse(err error) *eth.JSONRPCError {
func GetErrorResponse(err error) eth.JSONRPCError {
errorCode := GetErrorCode(err)
if errorCode == 0 {
return nil
}

return &eth.JSONRPCError{
Code: errorCode,
Message: err.Error(),
}
return eth.NewJSONRPCError(errorCode, err.Error(), nil)
}

var (
Expand Down
33 changes: 11 additions & 22 deletions pkg/server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,16 @@ func httpHandler(c echo.Context) error {
// level.Debug(cc.logger).Log("msg", "after call transformer#Transform")

if err != nil {
err1 := errors.Cause(err)
if err != err1 {
if err.Error() == nil {
cc.GetErrorLogger().Log("err", err.Error())
return cc.JSONRPCError(&eth.JSONRPCError{
Code: 100,
Message: err1.Error(),
})
return cc.JSONRPCError(err)
}

return err
return err.Error()
}

// Allow transformer to return an explicit JSON error
if jerr, isJSONErr := result.(*eth.JSONRPCError); isJSONErr {
if jerr, isJSONErr := result.(eth.JSONRPCError); isJSONErr {
return cc.JSONRPCError(jerr)
}

Expand Down Expand Up @@ -280,23 +276,19 @@ func websocketHandler(c echo.Context) error {

cc.rpcReq = &rpcReq

result, err := cc.transformer.Transform(&rpcReq, c)
result, jsonError := cc.transformer.Transform(&rpcReq, c)

response := result

if err != nil {
err1 := errors.Cause(err)
if err != err1 {
cc.GetErrorLogger().Log("err", err.Error())
response = cc.GetJSONRPCError(&eth.JSONRPCError{
Code: 100,
Message: err1.Error(),
})
if jsonError != nil {
if jsonError.Error() == nil {
cc.GetErrorLogger().Log("err", jsonError.Error())
response = jsonError
}
}

// Allow transformer to return an explicit JSON error
if jerr, isJSONErr := response.(*eth.JSONRPCError); isJSONErr {
if jerr, isJSONErr := response.(eth.JSONRPCError); isJSONErr {
response = cc.GetJSONRPCError(jerr)
} else {
response, err = cc.GetJSONRPCResult(response)
Expand Down Expand Up @@ -340,10 +332,7 @@ func errorHandler(err error, c echo.Context) {
cc, ok := myctx.(*myCtx)
if ok {
cc.GetErrorLogger().Log("err", err.Error())
if err := cc.JSONRPCError(&eth.JSONRPCError{
Code: 100,
Message: err.Error(),
}); err != nil {
if err := cc.JSONRPCError(eth.NewJSONRPCError(100, err.Error(), nil)); err != nil {
cc.GetErrorLogger().Log("msg", "reply to client", "err", err.Error())
}
return
Expand Down
6 changes: 3 additions & 3 deletions pkg/server/myctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (c *myCtx) JSONRPCResult(result interface{}) error {
return c.JSON(http.StatusOK, response)
}

func (c *myCtx) GetJSONRPCError(err *eth.JSONRPCError) *eth.JSONRPCResult {
func (c *myCtx) GetJSONRPCError(err eth.JSONRPCError) *eth.JSONRPCResult {
var id json.RawMessage
if c.rpcReq != nil && c.rpcReq.ID != nil {
id = c.rpcReq.ID
Expand All @@ -45,11 +45,11 @@ func (c *myCtx) GetJSONRPCError(err *eth.JSONRPCError) *eth.JSONRPCResult {
}
}

func (c *myCtx) JSONRPCError(err *eth.JSONRPCError) error {
func (c *myCtx) JSONRPCError(err eth.JSONRPCError) error {
resp := c.GetJSONRPCError(err)

if !c.Response().Committed {
err := c.JSON(http.StatusInternalServerError, resp)
err := c.JSON(http.StatusOK, resp)
c.logger.Log("Internal server error", err)
return err
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ func (s *Server) Start() error {
}

https := (s.httpsKey != "" && s.httpsCert != "")
level.Warn(s.logger).Log("listen", s.address, "qtum_rpc", s.qtumRPCClient.URL, "msg", "proxy started", "https", https)
// TODO: Upgrade golang to 1.15 to support s.qtumRPCClient.GetURL().Redacted() here
url := s.qtumRPCClient.URL
level.Info(s.logger).Log("listen", s.address, "qtum_rpc", url, "msg", "proxy started", "https", https)

if https {
level.Info(s.logger).Log("msg", "SSL enabled")
Expand Down
4 changes: 2 additions & 2 deletions pkg/transformer/eth_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ func (p *ProxyETHAccounts) Method() string {
return "eth_accounts"
}

func (p *ProxyETHAccounts) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, error) {
func (p *ProxyETHAccounts) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) {
return p.request()
}

func (p *ProxyETHAccounts) request() (eth.AccountsResponse, error) {
func (p *ProxyETHAccounts) request() (eth.AccountsResponse, eth.JSONRPCError) {
var accounts eth.AccountsResponse

for _, acc := range p.Accounts {
Expand Down
6 changes: 3 additions & 3 deletions pkg/transformer/eth_blockNumber.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ func (p *ProxyETHBlockNumber) Method() string {
return "eth_blockNumber"
}

func (p *ProxyETHBlockNumber) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, error) {
func (p *ProxyETHBlockNumber) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) {
return p.request()
}

func (p *ProxyETHBlockNumber) request() (*eth.BlockNumberResponse, error) {
func (p *ProxyETHBlockNumber) request() (*eth.BlockNumberResponse, eth.JSONRPCError) {
qtumresp, err := p.Qtum.GetBlockCount()
if err != nil {
return nil, err
return nil, eth.NewCallbackError(err.Error())
}

// qtum res -> eth res
Expand Down
Loading

0 comments on commit a746d4e

Please sign in to comment.