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.
251# Before each test, sync the headers chain.252test_node.request_headers_and_sync(locator=[tip])254# Now try a SENDCMPCT message with too-low version255test_node.send_and_ping(msg_sendcmpct(announce=True, version=1))256check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)258# Headers sync before next test.259test_node.request_headers_and_sync(locator=[tip])261# Now try a SENDCMPCT message with too-high version262test_node.send_and_ping(msg_sendcmpct(announce=True, version=3))263check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)265# Headers sync before next test.266test_node.request_headers_and_sync(locator=[tip])268# Now try a SENDCMPCT message with valid version, but announce=False269test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))270check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)272# Headers sync before next test.273test_node.request_headers_and_sync(locator=[tip])275# Finally, try a SENDCMPCT message with announce=True276test_node.send_and_ping(msg_sendcmpct(announce=True, version=2))277check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)279# Try one more time (no headers sync should be needed!)280check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)282# Try one more time, after turning on sendheaders283test_node.send_and_ping(msg_sendheaders())284check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)286# Try one more time, after sending a version=1, announce=false message.287test_node.send_and_ping(msg_sendcmpct(announce=False, version=1))288check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)290# Now turn off announcements291test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))292check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message)294# BIP152 mandates that the announce field of a sendcmpct message is a295# boolean and MUST have a value of either 1 or 0. Sending any other value296# should be treated as misbehavior and lead to a disconnect.297def test_invalid_sendcmpct_announce(self):298node = self.nodes[0]299bad_peer = node.add_p2p_connection(TestP2PConn())300msg = msg_sendcmpct(announce=2, version=2)301with node.assert_debug_log(['invalid sendcmpct announce field']):302bad_peer.send_await_disconnect(msg)304# This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.305# Note, these are not consensus-invalid blocks, but improperly constructed cmpctblock messages.306def test_invalid_cmpctblock_message(self):307# Make a high-bandwidth peer308hb_peer = self.nodes[0].add_p2p_connection(TestP2PConn())309self.request_cb_announcements(hb_peer)310self.make_peer_hb_to_candidate(self.nodes[0], hb_peer)311self.assert_highbandwidth_states(self.nodes[0], idx=-1, hb_to=True, hb_from=True)313# Make a low-bandwidth peer314lb_peer = self.nodes[0].add_p2p_connection(TestP2PConn())315self.request_cb_announcements(lb_peer)316self.assert_highbandwidth_states(self.nodes[0], idx=-1, hb_to=False, hb_from=True)318# Construct an invalid cmpctblock message319self.generate(self.nodes[0], COINBASE_MATURITY + 1)320block = self.build_block_on_tip(self.nodes[0])321cmpct_block = P2PHeaderAndShortIDs()322cmpct_block.header = CBlockHeader(block)323cmpct_block.prefilled_txn_length = 1324too_high_prefill_idx = 1325prefilled_txn = PrefilledTransaction(too_high_prefill_idx, block.vtx[0])326cmpct_block.prefilled_txn = [prefilled_txn]328# Test an unsolicited invalid cmpctblock from an HB peer.329hb_peer.send_await_disconnect(msg_cmpctblock(cmpct_block))330assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)332# Test a solicited invalid cmpctblock from a non-HB peer.333lb_peer.send_header_for_blocks([block])334lb_peer.wait_for_getdata([block.hash_int], timeout=30)335lb_peer.send_await_disconnect(msg_cmpctblock(cmpct_block))336assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)338# Compare the generated shortids to what we expect based on BIP 152, given339# bitcoind's choice of nonce.340def test_compactblock_construction(self, test_node):341node = self.nodes[0]342# Generate a bunch of transactions.343self.generate(node, COINBASE_MATURITY + 1)344num_transactions = 25346segwit_tx_generated = False347for _ in range(num_transactions):348hex_tx = self.wallet.send_self_transfer(from_node=self.nodes[0])['hex']349tx = tx_from_hex(hex_tx)350if not tx.wit.is_null():351segwit_tx_generated = True353assert segwit_tx_generated # check that our test is not broken355# Wait until we've seen the block announcement for the resulting tip356tip = int(node.getbestblockhash(), 16)357test_node.wait_for_block_announcement(tip)359# Make sure we will receive a fast-announce compact block360self.request_cb_announcements(test_node)362# Now mine a block, and look at the resulting compact block.363test_node.clear_block_announcement()364block_hash = int(self.generate(node, 1)[0], 16)366# Store the raw block in our internal format.367block = from_hex(CBlock(), node.getblock("%064x" % block_hash, False))369# Wait until the block was announced (via compact blocks)370test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)372# Now fetch and check the compact block373header_and_shortids = None374with p2p_lock:375# Convert the on-the-wire representation to absolute indexes376header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)377self.check_compactblock_construction_from_block(header_and_shortids, block_hash, block)379# Now fetch the compact block using a normal non-announce getdata380test_node.clear_block_announcement()381inv = CInv(MSG_CMPCT_BLOCK, block_hash)382test_node.send_without_ping(msg_getdata([inv]))384test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)386# Now fetch and check the compact block387header_and_shortids = None388with p2p_lock:389# Convert the on-the-wire representation to absolute indexes390header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)391self.check_compactblock_construction_from_block(header_and_shortids, block_hash, block)393def check_compactblock_construction_from_block(self, header_and_shortids, block_hash, block):394# Check that we got the right block!395assert_equal(header_and_shortids.header.hash_int, block_hash)397# Make sure the prefilled_txn appears to have included the coinbase398assert len(header_and_shortids.prefilled_txn) >= 1399assert_equal(header_and_shortids.prefilled_txn[0].index, 0)401# Check that all prefilled_txn entries match what's in the block.402for entry in header_and_shortids.prefilled_txn:403# This checks the non-witness parts of the tx agree404assert_equal(entry.tx.txid_hex, block.vtx[entry.index].txid_hex)406# And this checks the witness407assert_equal(entry.tx.wtxid_hex, block.vtx[entry.index].wtxid_hex)409# Check that the cmpctblock message announced all the transactions.410assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))412# And now check that all the shortids are as expected as well.413# Determine the siphash keys to use.414[k0, k1] = header_and_shortids.get_siphash_keys()416index = 0417while index < len(block.vtx):418if (len(header_and_shortids.prefilled_txn) > 0 and419header_and_shortids.prefilled_txn[0].index == index):420# Already checked prefilled transactions above421header_and_shortids.prefilled_txn.pop(0)422else:423tx_hash = block.vtx[index].wtxid_int424shortid = calculate_shortid(k0, k1, tx_hash)425assert_equal(shortid, header_and_shortids.shortids[0])426header_and_shortids.shortids.pop(0)427index += 1429# Test that bitcoind requests compact blocks when we announce new blocks430# via header or inv, and that responding to getblocktxn causes the block431# to be successfully reconstructed.432def test_compactblock_requests(self, test_node):433node = self.nodes[0]434# Try announcing a block with an inv or header, expect a compactblock435# request436for announce in ["inv", "header"]:437block = self.build_block_on_tip(node)439if announce == "inv":440test_node.send_without_ping(msg_inv([CInv(MSG_BLOCK, block.hash_int)]))441test_node.wait_for_getheaders(timeout=30)442test_node.send_header_for_blocks([block])443else:444test_node.send_header_for_blocks([block])445test_node.wait_for_getdata([block.hash_int], timeout=30)446assert_equal(test_node.last_message["getdata"].inv[0].type, 4)448# Send back a compactblock message that omits the coinbase449comp_block = HeaderAndShortIDs()450comp_block.header = CBlockHeader(block)451comp_block.nonce = 0452[k0, k1] = comp_block.get_siphash_keys()453coinbase_hash = block.vtx[0].wtxid_int454comp_block.shortids = [calculate_shortid(k0, k1, coinbase_hash)]455test_node.clear_getblocktxn()456test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))457assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)458# Expect a getblocktxn message that requests the coinbase.459self.getblocktxn_expected(test_node, block.hash_int, indices=[0])461# Send the coinbase, and verify that the tip advances.462msg = msg_blocktxn()463msg.block_transactions.blockhash = block.hash_int464msg.block_transactions.transactions = [block.vtx[0]]465test_node.send_and_ping(msg)466assert_equal(node.getbestblockhash(), block.hash_hex)468# Create a chain of transactions from given utxo, and add to a new block.469def build_block_with_transactions(self, node, utxo, num_transactions):470block = self.build_block_on_tip(node)472for _ in range(num_transactions):473tx = CTransaction()474tx.vin.append(CTxIn(COutPoint(utxo[0], utxo[1]), b''))475tx.vout.append(CTxOut(utxo[2] - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))476utxo = [tx.txid_int, 0, tx.vout[0].nValue]477block.vtx.append(tx)479block.hashMerkleRoot = block.calc_merkle_root()480block.solve()481return block483# Test that we only receive getblocktxn requests for transactions that the484# node needs, and that responding to them causes the block to be485# reconstructed.486def test_getblocktxn_requests(self, test_node):487node = self.nodes[0]489def test_getblocktxn_response(compact_block, peer, expected_result):490msg = msg_cmpctblock(compact_block.to_p2p())491peer.clear_getblocktxn()492peer.send_and_ping(msg)493self.getblocktxn_expected(peer, compact_block.header.hash_int, expected_result)495def test_tip_after_message(node, peer, msg, tip):496peer.send_and_ping(msg)497assert_equal(int(node.getbestblockhash(), 16), tip)499# First try announcing compactblocks that won't reconstruct, and verify500# that we receive getblocktxn messages back.
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.