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.
751comp_block.initialize_from_block(block)752test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))754tips = node.getchaintips()755found = False756for x in tips:757if x["hash"] == block.hash_hex:758assert_equal(x["status"], "headers-only")759found = True760break761assert found763# Requesting this block via getblocktxn should silently fail764# (to avoid fingerprinting attacks).765msg = msg_getblocktxn()766msg.block_txn_request = BlockTransactionsRequest(block.hash_int, [0])767with p2p_lock:768test_node.last_message.pop("blocktxn", None)769test_node.send_and_ping(msg)770with p2p_lock:771assert "blocktxn" not in test_node.last_message773def test_end_to_end_block_relay(self, listeners):774node = self.nodes[0]775utxo = self.utxos.pop(0)777block = self.build_block_with_transactions(node, utxo, 10)779[l.clear_block_announcement() for l in listeners]781# serialize without witness (this block has no witnesses anyway).782# TODO: repeat this test with witness tx's to a segwit node.783node.submitblock(block.serialize().hex())785for l in listeners:786l.wait_until(lambda: "cmpctblock" in l.last_message, timeout=30)787with p2p_lock:788for l in listeners:789assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.hash_int, block.hash_int)791# Test that we don't get disconnected if we relay a compact block with valid header,792# but invalid transactions.793def test_invalid_tx_in_compactblock(self, test_node):794node = self.nodes[0]795utxo = self.utxos.pop(0)797block = self.build_block_with_transactions(node, utxo, 5)798block.hashMerkleRoot = block.calc_merkle_root()799# Drop the coinbase witness but include the witness commitment.800add_witness_commitment(block)801block.vtx[0].wit.vtxinwit = []802block.solve()804# Now send the compact block with all transactions prefilled, and805# verify that we don't get disconnected.806comp_block = HeaderAndShortIDs()807comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)808msg = msg_cmpctblock(comp_block.to_p2p())809test_node.send_and_ping(msg)811# Check that the tip didn't advance812assert_not_equal(node.getbestblockhash(), block.hash_hex)813test_node.sync_with_ping()815# Re-establish a proper witness commitment with the coinbase witness, but816# invalidate the last tx in the block.817block.vtx[4].vin[0].scriptSig = CScript([OP_RETURN])818block.hashMerkleRoot = block.calc_merkle_root()819add_witness_commitment(block)820block.solve()822# This will lead to a consensus failure for which we also won't be disconnected but which823# will be cached.824comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)825msg = msg_cmpctblock(comp_block.to_p2p())826test_node.send_and_ping(msg)828# The tip still didn't advance.829assert_not_equal(node.getbestblockhash(), block.hash_hex)830test_node.sync_with_ping()832# The failure above was cached. Submitting the compact block again will return a cached833# consensus error (the code path is different) and still not get us disconnected (nor834# advance the tip).835test_node.send_and_ping(msg)836assert_not_equal(node.getbestblockhash(), block.hash_hex)837test_node.sync_with_ping()839# Now, announcing a second block building on top of the invalid one will get us disconnected.840block.hashPrevBlock = block.hash_int841block.solve()842comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)843msg = msg_cmpctblock(comp_block.to_p2p())844test_node.send_await_disconnect(msg)846def test_empty_getblocktxn_disconnects(self):847self.log.info("Testing empty getblocktxn disconnects the peer...")848node = self.nodes[0]849block_hash = int(node.getbestblockhash(), 16)850peer = node.add_p2p_connection(P2PInterface())851msg = msg_getblocktxn()852msg.block_txn_request = BlockTransactionsRequest(blockhash=block_hash, indexes=[])853with node.assert_debug_log(['getblocktxn received with no transaction indexes']):854peer.send_without_ping(msg)855peer.wait_for_disconnect()857# peer generates a block and sends it to node, which makes the peer a858# candidate for high-bandwidth 'to' (up to 3 peers according to BIP 152)859def make_peer_hb_to_candidate(self, node, peer):860block = self.build_block_on_tip(node)861peer.send_and_ping(msg_block(block))863# Helper for enabling cb announcements864# Send the sendcmpct request and sync headers865def request_cb_announcements(self, peer):866node = self.nodes[0]867tip = node.getbestblockhash()868peer.get_headers(locator=[int(tip, 16)], hashstop=0)869peer.send_and_ping(msg_sendcmpct(announce=True, version=2))871def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):872node = self.nodes[0]874self.make_peer_hb_to_candidate(node, delivery_peer)875block, cmpct_block = self.announce_cmpct_block(node, stalling_peer)877for tx in block.vtx[1:]:878delivery_peer.send_without_ping(msg_tx(tx))879delivery_peer.sync_with_ping()880mempool = node.getrawmempool()881for tx in block.vtx[1:]:882assert tx.txid_hex in mempool884delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))885assert_equal(node.getbestblockhash(), block.hash_hex)887self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])889# Now test that delivering an invalid compact block won't break relay891block, cmpct_block = self.announce_cmpct_block(node, stalling_peer)892for tx in block.vtx[1:]:893delivery_peer.send_without_ping(msg_tx(tx))894delivery_peer.sync_with_ping()896cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()]897cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]899cmpct_block.use_witness = True900delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))901assert_not_equal(node.getbestblockhash(), block.hash_hex)903msg = msg_no_witness_blocktxn()904msg.block_transactions.blockhash = block.hash_int905msg.block_transactions.transactions = block.vtx[1:]906stalling_peer.send_and_ping(msg)907assert_equal(node.getbestblockhash(), block.hash_hex)909# assert the RPC getpeerinfo boolean fields `bip152_hb_{to, from}`910# match the given parameters for the peer at idx of a given node911@staticmethod912def assert_highbandwidth_states(node, idx, hb_to, hb_from):913peerinfo = node.getpeerinfo()[idx]914assert_equal(peerinfo['bip152_hb_to'], hb_to)915assert_equal(peerinfo['bip152_hb_from'], hb_from)917def test_highbandwidth_mode_states_via_getpeerinfo(self):918# create new p2p connection for a fresh state w/o any prior sendcmpct messages sent919hb_test_node = self.nodes[0].add_p2p_connection(TestP2PConn())921# Newly created hb_test_node is the last connection.922hb_test_node_idx = -1924# initially, neither node has selected the other peer as high-bandwidth yet925self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=False)927# peer requests high-bandwidth mode by sending sendcmpct(1)928hb_test_node.send_and_ping(msg_sendcmpct(announce=True, version=2))929self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=False, hb_from=True)931# peer generates a block and sends it to node, which should932# select the peer as high-bandwidth (up to 3 peers according to BIP 152)933block = self.build_block_on_tip(self.nodes[0])934hb_test_node.send_and_ping(msg_block(block))935self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=True)937# peer requests low-bandwidth mode by sending sendcmpct(0)938hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))939self.assert_highbandwidth_states(self.nodes[0], hb_test_node_idx, hb_to=True, hb_from=False)941def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):942""" All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot943can only be taken by an outbound node unless prior attempts were done by an outbound944"""945node = self.nodes[0]947for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:948self.log.info(f"Setting {name} as high bandwidth peer")949self.make_peer_hb_to_candidate(node, peer)950block, cmpct_block = self.announce_cmpct_block(node, peer, 1)951msg = msg_blocktxn()952msg.block_transactions.blockhash = block.hash_int953msg.block_transactions.transactions = block.vtx[1:]954peer.send_and_ping(msg)955assert_equal(node.getbestblockhash(), block.hash_hex)956peer.clear_getblocktxn()958# Test the simple parallel download case...959for num_missing in [1, 5, 20]:960delivery_peer.clear_getblocktxn()961inbound_peer.clear_getblocktxn()962outbound_peer.clear_getblocktxn()964# Remaining low-bandwidth peer is stalling_peer, who announces first965assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])967block, cmpct_block = self.announce_cmpct_block(node, stalling_peer, num_missing, solicit=True)969delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))970# The second peer to announce should still get a getblocktxn971self.getblocktxn_expected(delivery_peer, block.hash_int)973inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))974with p2p_lock:975# The third inbound peer to announce should *not* get a getblocktxn976assert "getblocktxn" not in inbound_peer.last_message977assert_not_equal(node.getbestblockhash(), block.hash_hex)979outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))980# The third peer to announce should get a getblocktxn if outbound981self.getblocktxn_expected(outbound_peer, block.hash_int)983# Second peer completes the compact block first984msg = msg_blocktxn()985msg.block_transactions.blockhash = block.hash_int986msg.block_transactions.transactions = block.vtx[1:]987delivery_peer.send_and_ping(msg)988assert_equal(node.getbestblockhash(), block.hash_hex)990# Nothing bad should happen if we get a late fill from the first peer...991stalling_peer.send_and_ping(msg)992self.utxos.append([block.vtx[-1].txid_int, 0, block.vtx[-1].vout[0].nValue])994def test_compact_blocks_ignored(self):995node = self.nodes[0]997def build_compact_block():998# generate a compact block to send that will force a GETBLOCKTXN999utxo = self.utxos.pop(0)1000block = self.build_block_with_transactions(node, utxo, 10)
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.