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.
501def peer_connect(self, *, services=P2P_SERVICES, send_version, **kwargs):502create_conn = super().peer_connect(**kwargs)504if send_version:505self.peer_connect_send_version(services)507return create_conn509def peer_accept_connection(self, *args, services=P2P_SERVICES, **kwargs):510create_conn = super().peer_accept_connection(*args, **kwargs)511self.peer_connect_send_version(services)513return create_conn515# Message receiving methods517def on_message(self, message):518"""Receive message and dispatch message to appropriate callback.520We keep a count of how many of each message type has been received521and the most recent message of each type."""522with p2p_lock:523try:524msgtype = message.msgtype.decode('ascii')525self.message_count[msgtype] += 1526self.last_message[msgtype] = message527getattr(self, 'on_' + msgtype)(message)528except Exception:529print("ERROR delivering %s (%s)" % (repr(message), sys.exc_info()[0]))530raise532# Callback methods. Can be overridden by subclasses in individual test533# cases to provide custom message handling behaviour.535def on_open(self):536pass538def on_close(self):539pass541def on_addr(self, message): pass542def on_addrv2(self, message): pass543def on_block(self, message): pass544def on_blocktxn(self, message): pass545def on_cfcheckpt(self, message): pass546def on_cfheaders(self, message): pass547def on_cfilter(self, message): pass548def on_cmpctblock(self, message): pass549def on_feature(self, message): pass550def on_feefilter(self, message): pass551def on_filteradd(self, message): pass552def on_filterclear(self, message): pass553def on_filterload(self, message): pass554def on_getaddr(self, message): pass555def on_getblocks(self, message): pass556def on_getblocktxn(self, message): pass557def on_getdata(self, message): pass558def on_getheaders(self, message): pass559def on_headers(self, message): pass560def on_mempool(self, message): pass561def on_merkleblock(self, message): pass562def on_notfound(self, message): pass563def on_pong(self, message): pass564def on_sendaddrv2(self, message): pass565def on_sendcmpct(self, message): pass566def on_sendheaders(self, message): pass567def on_sendtxrcncl(self, message): pass568def on_tx(self, message): pass569def on_wtxidrelay(self, message): pass571def on_inv(self, message):572want = msg_getdata()573for i in message.inv:574if i.type != 0:575want.inv.append(i)576if len(want.inv):577self.send_without_ping(want)579def on_ping(self, message):580self.send_without_ping(msg_pong(message.nonce))582def on_verack(self, message):583pass585def on_version(self, message):586assert message.nVersion >= MIN_P2P_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_P2P_VERSION_SUPPORTED)587# for inbound connections, reply to version with own version message588# (could be due to v1 reconnect after a failed v2 handshake)589if not self.p2p_connected_to_node:590self.send_version()591self.reconnect = False592if message.nVersion >= 70016 and self.wtxidrelay:593self.send_without_ping(msg_wtxidrelay())594if self.support_addrv2:595self.send_without_ping(msg_sendaddrv2())596self.send_without_ping(msg_verack())597self.nServices = message.nServices598self.relay = message.relay599if self.p2p_connected_to_node:600self.send_without_ping(msg_getaddr())602# Connection helper methods604def wait_until(self, test_function_in, *, timeout=60, check_connected=True, check_interval=0.05):605def test_function():606if check_connected:607assert self.is_connected608return test_function_in()610wait_until_helper_internal(test_function, timeout=timeout, lock=p2p_lock, timeout_factor=self.timeout_factor, check_interval=check_interval)612def wait_for_connect(self, *, timeout=60):613def test_function():614return self.is_connected616self.wait_until(test_function, timeout=timeout, check_connected=False)618def wait_for_disconnect(self, *, timeout=60):619def test_function():620return not self.is_connected622self.wait_until(test_function, timeout=timeout, check_connected=False)624def wait_for_reconnect(self, *, timeout=60):625def test_function():626return self.is_connected and self.last_message.get('version') and not self.supports_v2_p2p627self.wait_until(test_function, timeout=timeout, check_connected=False)629# Message receiving helper methods631def wait_for_tx(self, txid, *, timeout=60):632def test_function():633if not self.last_message.get('tx'):634return False635return self.last_message['tx'].tx.txid_hex == txid637self.wait_until(test_function, timeout=timeout)639def wait_for_block(self, blockhash, *, timeout=60):640def test_function():641return self.last_message.get("block") and self.last_message["block"].block.hash_int == blockhash643self.wait_until(test_function, timeout=timeout)645def wait_for_header(self, blockhash, *, timeout=60):646def test_function():647last_headers = self.last_message.get('headers')648if not last_headers:649return False650return last_headers.headers[0].hash_int == int(blockhash, 16)652self.wait_until(test_function, timeout=timeout)654def wait_for_merkleblock(self, blockhash, *, timeout=60):655def test_function():656last_filtered_block = self.last_message.get('merkleblock')657if not last_filtered_block:658return False659return last_filtered_block.merkleblock.header.hash_int == int(blockhash, 16)661self.wait_until(test_function, timeout=timeout)663def wait_for_getdata(self, hash_list, *, timeout=60):664"""Waits for a getdata message.666The object hashes in the inventory vector must match the provided hash_list."""667def test_function():668last_data = self.last_message.get("getdata")669if not last_data:670return False671return [x.hash for x in last_data.inv] == hash_list673self.wait_until(test_function, timeout=timeout)675def wait_for_getheaders(self, block_hash=None, *, timeout=60):676"""Waits for a getheaders message containing a specific block hash.678If no block hash is provided, checks whether any getheaders message has been received by the node."""679def test_function():680last_getheaders = self.last_message.pop("getheaders", None)681if block_hash is None:682return last_getheaders683if last_getheaders is None:684return False685return block_hash == last_getheaders.locator.vHave[0]687self.wait_until(test_function, timeout=timeout)689def wait_for_inv(self, expected_inv, *, timeout=60):690"""Waits for an INV message and checks that the first inv object in the message was as expected."""691if len(expected_inv) > 1:692raise NotImplementedError("wait_for_inv() will only verify the first inv object")694def test_function():695return self.last_message.get("inv") and \696self.last_message["inv"].inv[0].type == expected_inv[0].type and \697self.last_message["inv"].inv[0].hash == expected_inv[0].hash699self.wait_until(test_function, timeout=timeout)701def wait_for_verack(self, *, timeout=60):702def test_function():703return "verack" in self.last_message705self.wait_until(test_function, timeout=timeout)707# Message sending helper functions709def send_version(self):710if self.on_connection_send_msg:711self.send_without_ping(self.on_connection_send_msg)712self.on_connection_send_msg = None # Never used again714def send_and_ping(self, message, *, timeout=60):715self.send_without_ping(message)716self.sync_with_ping(timeout=timeout)718def sync_with_ping(self, *, timeout=60):719"""Ensure ProcessMessages and SendMessages is called on this connection"""720# Sending two pings back-to-back, requires that the node calls721# `ProcessMessage` twice, and thus ensures `SendMessages` must have722# been called at least once723self.send_without_ping(msg_ping(nonce=0))724self.send_without_ping(msg_ping(nonce=self.ping_counter))726def test_function():727return self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter729self.wait_until(test_function, timeout=timeout)730self.ping_counter += 1733# One lock for synchronizing all data access between the network event loop (see734# NetworkThread below) and the thread running the test logic. For simplicity,735# P2PConnection acquires this lock whenever delivering a message to a P2PInterface.736# This lock should be acquired in the thread running the test logic to synchronize737# access to any data shared with the P2PInterface or P2PConnection.738p2p_lock = threading.Lock()741class NetworkThread(threading.Thread):742network_event_loop = None744def __init__(self):745super().__init__(name="NetworkThread")746# There is only one event loop and no more than one thread must be created747assert not self.network_event_loop749NetworkThread.listeners = {}750NetworkThread.protos = {}
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.