checksum0 / go-electrum

A pure Go ElectrumX JSON-RPC library.
MIT License
27 stars 26 forks source link

Unmarshaling error from response fails with: `cannot unmarshal object into Go struct field response.error of type string` #5

Open nkuba opened 1 year ago

nkuba commented 1 year ago

Responses unmarshaling don't work for errors returned by ElectrumX and Fulcrum servers.

I called the GetBlockHeader function with a block height that doesn't exist. https://github.com/checksum0/go-electrum/blob/b862ac442cf9f05c55a46eb060c7b547450808d3/electrum/block.go#L27 I observed the following error being returned:

Unmarshal received message failed: json: cannot unmarshal object into Go struct field response.error of type string

The reason for that is that ElectrumX, Fulcrum, and Electrs/Esplora are inconsistent when it comes to the error response format. Please see the examples (for Bitcoin Testnet servers):

ElectrumX

✗ echo '{"jsonrpc": "2.0", "method": "server.version", "id": 0}' | netcat 49.12.127.114 10068
{"jsonrpc":"2.0","result":["ElectrumX 1.16.0","1.4"],"id":0}

✗ echo '{"jsonrpc": "2.0", "method": "blockchain.block.header", "params": [4294967295], "id": 0}' | netcat 49.12.127.114 10068
{"jsonrpc":"2.0","error":{"code":1,"message":"height 4,294,967,295 out of range"},"id":0}

Fulcrum

✗ echo '{"jsonrpc": "2.0", "method": "server.version", "id": 0}' | netcat 203.132.94.196 51001
{"id":0,"jsonrpc":"2.0","result":["Fulcrum 1.8.2","1.4"]}

✗ echo '{"jsonrpc": "2.0", "method": "blockchain.block.header", "params": [4294967295], "id": 0}' | netcat 203.132.94.196 51001
{"error":{"code":1,"message":"Invalid height"},"id":0,"jsonrpc":"2.0"}

Electrs/Esplora

✗ echo '{"jsonrpc": "2.0", "method": "server.version", "id": 0}' | netcat 35.225.54.191 50001
{"id":0,"jsonrpc":"2.0","result":["electrs-esplora 0.4.1","1.4"]}

✗ echo '{"jsonrpc": "2.0", "method": "blockchain.block.header", "params": [4294967295], "id": 0}' | netcat 35.225.54.191 50001
{"error":"missing header","id":0,"jsonrpc":"2.0"}

The client handles correctly only the response returned by the Electrs/Esplora server, as only this response format can be unmarshaled to the response struct that assumes a string as an error: https://github.com/checksum0/go-electrum/blob/b862ac442cf9f05c55a46eb060c7b547450808d3/electrum/network.go#L124-L128

nkuba commented 1 year ago

Turns out this is a bug in the esplora/electrs (https://github.com/Blockstream/esplora/issues/453), as JSON-RPC 2.0 clearly defines the format for error object.