Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Electrum Protocol Server

satd ships a native Electrum protocol server (the electrum-proto crate), serving the JSON-RPC-over-TCP protocol that BlueWallet, Sparrow, Nunchuk, Electrum, and most hardware-wallet coordinators speak. It is a query layer over satd's own chainstate and address-history index — not a separate electrs / Fulcrum process with its own copy of the data. satd's combined index is larger on disk than a standalone electrs/Fulcrum index — the trade is disk for consistency and single-process operation (see Disk Footprint & Indices). See Native Protocol Architecture for the "why native + shared chainstate" rationale.

It is off by default. Enable with --electrum=1; it requires --addressindex=1 (for scripthash history) and --txindex=1 (for the confirmed-transaction and merkle-proof methods), both enforced at startup.

  • Protocol version: 1.4 — advertised as both protocol_min and protocol_max (satd serves a single protocol version).
  • Transport: line-delimited JSON-RPC over plain TCP (default 127.0.0.1:50001) and/or TLS (default port 50002). Expose over Tor / .onion rather than directly on the LAN.

Authentication. Electrum is loopback by default. It supports native TLS and mutual TLS (--electrumtlsbind + --electrummtls…); the unified bearer-token layer does not gate Electrum (client-cert principals are a documented future seam). See Authentication & Authorization.

Configuration

CLI flagDefaultNotes
--electrum=<0|1>0Enable the Electrum server. Requires --addressindex=1 and --txindex=1.
--electrumbind=<addr:port>127.0.0.1:50001Plain-TCP listener bind.
--electrumtlsbind=<addr:port>noneTLS listener bind (standard port 50002). Requires cert + key.
--electrumtlscert=<path>nonePEM TLS certificate.
--electrumtlskey=<path>nonePEM TLS private key.
--electrummtls=<0|1>0Require mutual TLS on the TLS listener.
--electrummtlsclientca=<path>nonePEM CA bundle to verify client certs when --electrummtls=1.
--electrummtlsclientallow=<subj>any CA-signedAllowlist of accepted client-cert CN / DNS-SAN values.
--electrummaxconns=<n>64Hard cap on simultaneously-open connections.
--electrummaxsubsperconn=<n>1000Per-connection scripthash subscription cap.
--electrumrequesttimeout=<secs>30Per-request handler timeout.
--electrummaxbatchrequests=<n>100Max requests per JSON-RPC batch line. Wallets (e.g. Sparrow) batch their whole gap-limit window of scripthash.subscribe calls at scan time, so a low cap fails the scan.
--electrummaxbroadcastpackagetxs=<n>25Max txs per blockchain.transaction.broadcast_package.
--electrumfeehistogramttl=<secs>10TTL for the mempool.get_fee_histogram cache.
--electrumbanner=<text>powered by satd <version>Override for server.banner.

The server runs on satd's isolated API runtime (--api-threads), so Electrum load cannot starve block connection.

Supported methods

A scripthash is the SHA-256 of an output scriptPubKey, reversed (hex), exactly as in the Electrum protocol.

Server / session

MethodDescription
server.versionNegotiate client/server software + protocol version.
server.pingKeepalive; returns null.
server.bannerServer banner text (configurable via --electrumbanner).
server.donation_addressConfigured donation address (empty if unset).
server.featuresFeature/identity dict: genesis hash, protocol_min/protocol_max (both 1.4), hosts, etc.
server.peers.subscribePeer-server discovery list (satd returns an empty set — no peer gossip).

Headers & blocks

MethodDescription
blockchain.headers.subscribeSubscribe to new-tip notifications; returns the current tip header and pushes on each new block.
blockchain.headers.getFetch a header by height.
blockchain.block.headerA block header (with an optional merkle proof to a checkpoint).
blockchain.block.headersA contiguous range of headers (with optional checkpoint proof).

Scripthash (address) queries

MethodDescription
blockchain.scripthash.get_historyConfirmed + mempool history for a scripthash.
blockchain.scripthash.get_balanceConfirmed + unconfirmed balance.
blockchain.scripthash.listunspentUnspent outputs for a scripthash.
blockchain.scripthash.get_mempoolMempool-only history for a scripthash.
blockchain.scripthash.get_first_useFirst block/tx that paid the scripthash (electrs-style extension).
blockchain.scripthash.subscribeSubscribe to a scripthash; pushes a new status hash whenever its history changes.
blockchain.scripthash.unsubscribeCancel a scripthash subscription.

Transactions

MethodDescription
blockchain.transaction.getRaw transaction by txid (verbose decode optional). Needs --txindex.
blockchain.transaction.get_merkleMerkle inclusion proof for a confirmed tx. Needs --txindex.
blockchain.transaction.id_from_posTxid at a (height, position), optionally with a merkle proof. Needs --txindex.
blockchain.transaction.broadcastSubmit a raw transaction to the network.
blockchain.transaction.broadcast_packageSubmit a package of transactions (bounded by --electrummaxbroadcastpackagetxs).

Fees

MethodDescription
blockchain.estimatefeeEstimated fee rate (BTC/kB) for a confirmation target.
blockchain.relayfeeThe node's minimum relay fee rate.
mempool.get_fee_histogramMempool fee-rate histogram (cached; TTL --electrumfeehistogramttl).

Subscriptions

Two push subscriptions are supported and counted against --electrummaxsubsperconn:

  • blockchain.headers.subscribe — a blockchain.headers.subscribe notification on every new tip.
  • blockchain.scripthash.subscribe — a blockchain.scripthash.subscribe notification carrying the new status hash whenever a watched scripthash's history changes (mempool or confirmed). Because the index is updated inside the same connect_block / disconnect_block batch as the chainstate, a subscriber can never observe a status out of sync with the tip.

Notes & differences

  • --txindex is required for blockchain.transaction.get / get_merkle / id_from_pos; --addressindex (on by default) backs every scripthash.* method.
  • satd advertises a single protocol version (protocol_min == protocol_max == 1.4); it does not negotiate a range.
  • server.peers.subscribe returns an empty list — satd does not participate in Electrum peer gossip.
  • The protocol layer is vendored from romanz/electrs (MIT; attribution in electrum-proto/vendor/electrs.MIT) and adapted to satd's AddressIndex trait over the shared RocksDB.