Skip to content
Back to skills

Zmq

ASecurity

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.

  • 31 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 8, 2026
ai-agentspythonbashnodedebuggingapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 22, 2026

npx -y skills add claude-dev-suite/claude-dev-suite --skill zmq --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Zmq?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Zmq
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/claude-dev-suite-zmq/badge)](https://www.skillsdirectory.com/skills/claude-dev-suite-zmq)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bitcoin-core-zmq
description: |
  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.
allowed-tools: Read, Grep, Glob
---

# 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`:
```ini
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

| Topic | Payload | Notes |
|-------|---------|-------|
| `rawblock` | full block bytes | At every new tip block. |
| `rawtx` | full tx bytes | Mempool admission + block inclusion. |
| `hashblock` | 32-byte block hash | Lightweight tip notification. |
| `hashtx` | 32-byte txid | Lightweight tx notification. |
| `sequence` | txid + status byte | Mempool 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`):
```python
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):
```js
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

```python
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`

```bash
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

- [rpc/SKILL.md](../rpc/SKILL.md)
- [rest-api/SKILL.md](../rest-api/SKILL.md)
- [../../infrastructure/electrs/SKILL.md](../../infrastructure/electrs/SKILL.md)
- [../../infrastructure/btcpay/SKILL.md](../../infrastructure/btcpay/SKILL.md)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.