Skip to content

Commit

Permalink
Merge pull request checksum0#1 from keep-network/json-rpc-error-unmar…
Browse files Browse the repository at this point in the history
…shal

Handle error string returned in the JSON-RPC response
  • Loading branch information
lukasz-zimnoch authored May 16, 2023
2 parents b862ac4 + 94663e5 commit 567f2c1
Showing 1 changed file with 37 additions and 6 deletions.
43 changes: 37 additions & 6 deletions electrum/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ func NewClientSSL(ctx context.Context, addr string, config *tls.Config) (*Client
return c, nil
}

// JSON-RPC 2.0 Error Object
// See: https://www.jsonrpc.org/specificationJSON#error_object
type apiErr struct {
Code int `json:"code"`
Message string `json:"message"`
Expand All @@ -121,10 +123,39 @@ func (e *apiErr) Error() string {
return fmt.Sprintf("errNo: %d, errMsg: %s", e.Code, e.Message)
}

// UnmarshalJSON defines a workaround for servers that respond with error
// that doesn't follow the JSON-RPC 2.0 Error Object format, i.e. electrs/esplora.
// See: https://github.com/Blockstream/esplora/issues/453
func (e *apiErr) UnmarshalJSON(data []byte) error {
var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
return fmt.Errorf("failed to unmarshal error [%s]: %v", data, err)
}

switch v := v.(type) {
case string:
e.Message = v
case map[string]interface{}:
if _, ok := v["code"]; ok {
e.Code = int(v["code"].(float64))
}

if _, ok := v["message"]; ok {
e.Message = fmt.Sprint(v["message"])
}
default:
return fmt.Errorf("unsupported type: %v", v)
}

return nil
}

// JSON-RPC 2.0 Response Object
// See: https://www.jsonrpc.org/specification#response_object
type response struct {
ID uint64 `json:"id"`
Method string `json:"method"`
Error string `json:"error"`
ID uint64 `json:"id"`
Method string `json:"method"`
Error *apiErr `json:"error"`
}

func (s *Client) listen() {
Expand All @@ -150,11 +181,11 @@ func (s *Client) listen() {
err := json.Unmarshal(bytes, msg)
if err != nil {
if DebugMode {
log.Printf("Unmarshal received message failed: %v", err)
log.Printf("unmarshal received message [%s] failed: [%v]", bytes, err)
}
result.err = fmt.Errorf("Unmarshal received message failed: %v", err)
} else if msg.Error != "" {
result.err = errors.New(msg.Error)
} else if msg.Error != nil {
result.err = msg.Error
}

if len(msg.Method) > 0 {
Expand Down

0 comments on commit 567f2c1

Please sign in to comment.