bitcoin-core-zmq

v2026.09.24

ZeroMQ notifications from Bitcoin Core: rawblock, rawtx, hashblock, hashtx, sequence. Subscribe over TCP/IPC, integration patterns for Electrs, BTCPay, Lightning nodes. USE WHEN: building real-time integrations with bitcoind, monitoring mempool sequence, integrating LN nodes.

GitHub
安装命令
npx skhub add claude-dev-suite/bitcoin-core-zmq
Markdown
SKILL.md

ZMQ Notifications

Bitcoin Core can publish events via ZeroMQ for low-latency, push-based integration. Beats polling RPC for real-time apps.

Configuration

bitcoin.conf:

zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28333
zmqpubhashblock=tcp://127.0.0.1:28334
zmqpubhashtx=tcp://127.0.0.1:28335
zmqpubsequence=tcp://127.0.0.1:28336

Each topic on its own port (or share — but separate is cleaner).

Bind address forms:

  • tcp://127.0.0.1:port — local-only.
  • tcp://0.0.0.0:port — all interfaces (firewall it!).
  • ipc:///tmp/socket.ipc — Unix socket, fast for local.
  • inproc://... — same-process only (rarely useful from external client).

Topics

TopicPayloadNotes
rawblockfull block bytesAt every new tip block.
rawtxfull tx bytesMempool admission + block inclusion.
hashblock32-byte block hashLightweight tip notification.
hashtx32-byte txidLightweight tx notification.
sequencetxid + status byteMempool sequence (Add/Remove/...).

All hashes on the wire (hashblock, hashtx, and the hash prefix of sequence) are already in reversed byte order — the same order RPC and block explorers display — and Core reverses them in src/zmq/zmqpublishnotifier.cpp before sending. Hex-encode the bytes as received. Reversing again yields a hash no RPC lookup will match.

When assumeutxo is in use, rawblock and hashblock are not issued for historical blocks connected to the background validation chainstate (documented in doc/zmq.md since Core 26.0, December 2023; still stated in v31.1, July 2026).

Sequence message format

[32 bytes] hash
[1 byte]   status: 'A' = mempool add
                   'R' = mempool remove (eviction or mined)
                   'C' = block connect (new tip)
                   'D' = block disconnect (reorg)
[8 bytes]  mempool sequence number (only for A/R)

The sequence number is monotonic per node restart and lets clients detect missed messages.

Client subscription

Python (pyzmq):

import zmq

ctx = zmq.Context()
sock = ctx.socket(zmq.SUB)
sock.connect("tcp://127.0.0.1:28333")
sock.setsockopt_string(zmq.SUBSCRIBE, "rawtx")

while True:
    topic, body, seq = sock.recv_multipart()
    print(topic, len(body), int.from_bytes(seq, "little"))

The third frame is a 4-byte little-endian message counter (per topic since node start) — useful to detect drops.

Node (zeromq package):

const zmq = require("zeromq");
const sock = new zmq.Subscriber();
sock.connect("tcp://127.0.0.1:28332");
sock.subscribe("rawblock");
for await (const [topic, msg, seq] of sock) {
    console.log(topic.toString(), msg.length);
}

Throughput considerations

  • ZMQ uses unbounded buffers by default → if client is slow, memory grows. Set HWM (set HighWaterMark) on subscriber to drop old messages instead.
  • Order of arrival: per topic per peer in order; cross-topic ordering not guaranteed (subscribe to multiple topics → use sequence number to reconcile).

Common patterns

Lightning node monitoring

LND, CLN, LDK use ZMQ to know when mempool / block events affect their channels:

  • rawblock → check if commitment tx confirmed.
  • rawtx → fee bump opportunities.
  • sequence → detect a counterparty broadcast quickly.

BTCPay Server

Subscribes to rawblock + rawtx for invoice status updates.

Indexers (Electrs, Fulcrum)

Use hashblock for tip notification → trigger incremental update of the index.

Mempool watcher

sock.subscribe("sequence")
seen = set()
while True:
    topic, body, _ = sock.recv_multipart()
    txid = body[:32].hex()
    status = chr(body[32])
    if status == "A": seen.add(txid)
    elif status in ("R", "C"): seen.discard(txid)

Failure modes

  • Connection drop — ZMQ reconnects automatically on TCP. After reconnect, you may have missed messages — use sequence numbers + RPC catch-up to reconcile.
  • Slow consumer — without HWM, memory bloats. Set sock.set(zmq.RCVHWM, 1000) to cap.
  • TCP across hosts — fine for dev, but be aware of firewall + encryption (no built-in TLS for ZMQ; use stunnel or VPN).

RPC alternative: getzmqnotifications

bitcoin-cli getzmqnotifications

Returns currently configured notification endpoints — useful for debugging "is my client listening on the right port?".

Common bugs

  • Subscribing without setting topic filter (SUBSCRIBE to "" = receive all from publisher) — gets blocks even if subscribed only to "tx".
  • Treating hashblock as ordered with rawtx for the same tx that just confirmed — they're independent topics.
  • Setting zmqpubrawblock=tcp://0.0.0.0:28332 and exposing to internet — a malicious peer can drain bandwidth.

See also

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

Sep 24, 2026

分类

未分类

许可证

MIT

源路径

skills/bitcoin/core/zmq

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1