Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2014-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.6"""7ZMQ example using python3's asyncio9Bitcoin should be started with the command line arguments:10bitcoind -testnet4 -daemon \11-zmqpubrawtx=tcp://127.0.0.1:28332 \12-zmqpubrawblock=tcp://127.0.0.1:28332 \13-zmqpubhashtx=tcp://127.0.0.1:28332 \14-zmqpubhashblock=tcp://127.0.0.1:28332 \15-zmqpubsequence=tcp://127.0.0.1:2833217We use the asyncio library here. `self.handle()` installs itself as a18future at the end of the function. Since it never returns with the event19loop having an empty stack of futures, this creates an infinite loop. An20alternative is to wrap the contents of `handle` inside `while True`.22A blocking example using python 2.7 can be obtained from the git history:23https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py24"""26import asyncio27import zmq28import zmq.asyncio29import signal30import struct31import sys33if (sys.version_info.major, sys.version_info.minor) < (3, 5):34print("This example only works with Python 3.5 and greater")35sys.exit(1)37port = 2833239class ZMQHandler():40def __init__(self):41self.loop = asyncio.get_event_loop()42self.zmqContext = zmq.asyncio.Context()44self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)45self.zmqSubSocket.setsockopt(zmq.RCVHWM, 0)46self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")47self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")48self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")49self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")50self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "sequence")51self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)53async def handle(self) :54topic, body, seq = await self.zmqSubSocket.recv_multipart()55sequence = "Unknown"56if len(seq) == 4:57sequence = str(struct.unpack('<I', seq)[-1])58if topic == b"hashblock":59print('- HASH BLOCK ('+sequence+') -')60print(body.hex())61elif topic == b"hashtx":62print('- HASH TX ('+sequence+') -')63print(body.hex())64elif topic == b"rawblock":65print('- RAW BLOCK HEADER ('+sequence+') -')66print(body[:80].hex())67elif topic == b"rawtx":68print('- RAW TX ('+sequence+') -')69print(body.hex())70elif topic == b"sequence":71hash = body[:32].hex()72label = chr(body[32])73mempool_sequence = None if len(body) != 32+1+8 else struct.unpack("<Q", body[32+1:])[0]74print('- SEQUENCE ('+sequence+') -')75print(hash, label, mempool_sequence)76# schedule ourselves to receive the next message77asyncio.ensure_future(self.handle())79def start(self):80self.loop.add_signal_handler(signal.SIGINT, self.stop)81self.loop.create_task(self.handle())82self.loop.run_forever()84def stop(self):85self.loop.stop()86self.zmqContext.destroy()88daemon = ZMQHandler()89daemon.start()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.