Skip to content

Electrum RPC: unknown methods close the connection without a JSON-RPC error reply #219

@EddieHouston

Description

@EddieHouston

Problem

Any method without a dispatch arm in handle_command — a typo, an unimplemented
Electrum method (blockchain.scripthash.get_mempool,
blockchain.transaction.get_tsc_merkle), or blockchain.scripthash.get_balance on
Liquid builds (where the arm is compiled out via #[cfg(not(feature = "liquid"))]) —
causes the server to close the TCP connection without writing any JSON-RPC response.
Clients cannot distinguish an intentionally unsupported method from an outage, and
retrying clients turn one cheap error reply into repeated TCP+TLS reconnects.

Inside a batch request, a single unknown method kills the whole batch and the
connection; the remaining requests are never answered.

Cause

The catch-all arm in handle_command:

  &_ => bail!("unknown method {} {:?}", method, params),

bail! returns Err from the whole function, bypassing the error-to-JSON conversion
a few lines below — that conversion only sees errors that dispatched handlers assign
into result. The unknown-method error instead propagates through the ? in
handle_value and handle_replies, and run() logs "connection handling failed"
and shuts the socket down.

Fix

Produce the error as a value inside result, so it flows through the existing
conversion and is returned as a normal JSON-RPC error reply:

  &_ => Err(format!("unknown method {}", method).into()),
  • The connection stays open, matching other handler errors in electrs and other
    Electrum server implementations (ElectrumX, Fulcrum).
  • params are deliberately omitted from the message so client-controlled input is
    not echoed back; only the method name is included.
  • Batches now answer their remaining requests when one entry has an unknown method.

Out of scope

Malformed input still drops the connection, unchanged: invalid JSON, requests
without a string method / array params / id, oversized batches, invalid UTF-8,
and TLS bytes on the plaintext port. The first two arguably deserve error replies as
well (with "id": null per JSON-RPC), but that is a larger change than this fix.

Testing

Against a local instance:

  echo '{"jsonrpc":"2.0","id":1,"method":"blockchain.scripthash.get_mempool","params":["e573ed3c89a107e4c5b67cebc6a6cadb2faa40fb02a7c5092d9b4d4f118a3efe"]}' | nc localhost 50001

Before fix we see: connection closes with no payload.
After fix we should see: {"error":"unknown method blockchain.scripthash.get_mempool","id":1,"jsonrpc":"2.0"}
and the connection remains open.
A batch mixing server.ping with an unknown method should return results for both entries instead of dropping the connection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions