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) 2024-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.5"""Test getblocktemplate RPC in proposal mode7Generate several blocks and test them against the getblocktemplate RPC.8"""10from concurrent.futures import ThreadPoolExecutor12import copy14from test_framework.blocktools import (15create_block,16add_witness_commitment,17NORMAL_GBT_REQUEST_PARAMS,18)20from test_framework.test_framework import BitcoinTestFramework21from test_framework.util import (22assert_equal,23assert_raises_rpc_error,24)26from test_framework.messages import (27BLOCK_HEADER_SIZE,28uint256_from_compact,29)31from test_framework.wallet import (32MiniWallet,33)35def assert_template(node, block, expect, *, rehash=True, submit=True, solve=True, expect_submit=None):36if rehash:37block.hashMerkleRoot = block.calc_merkle_root()39rsp = node.getblocktemplate(template_request={40'data': block.serialize().hex(),41'mode': 'proposal',42**NORMAL_GBT_REQUEST_PARAMS,43})44assert_equal(rsp, expect)45# Only attempt to submit invalid templates46if submit and expect is not None:47# submitblock runs checks in a different order, so may not return48# the same error49if expect_submit is None:50expect_submit = expect51if solve:52block.solve()53assert_equal(node.submitblock(block.serialize().hex()), expect_submit)55class MiningTemplateVerificationTest(BitcoinTestFramework):57def set_test_params(self):58self.num_nodes = 160def valid_block_test(self, node, block):61self.log.info("Valid block")62assert_template(node, block, None)64def cb_missing_test(self, node, block):65self.log.info("Bad input hash for coinbase transaction")66bad_block = copy.deepcopy(block)67bad_block.vtx[0].vin[0].prevout.hash += 168assert_template(node, bad_block, 'bad-cb-missing')70def block_without_transactions_test(self, node, block):71self.log.info("Block with no transactions")73no_tx_block = copy.deepcopy(block)74no_tx_block.vtx.clear()75no_tx_block.hashMerkleRoot = 076no_tx_block.solve()77assert_template(node, no_tx_block, 'bad-blk-length', rehash=False)79def truncated_final_transaction_test(self, node, block):80self.log.info("Truncated final transaction")81assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate,82template_request={83"data": block.serialize()[:-1].hex(),84"mode": "proposal",85**NORMAL_GBT_REQUEST_PARAMS,86}87)89def duplicate_transaction_test(self, node, block):90self.log.info("Duplicate transaction")91bad_block = copy.deepcopy(block)92bad_block.vtx.append(bad_block.vtx[0])93assert_template(node, bad_block, 'bad-txns-duplicate')95def thin_air_spending_test(self, node, block):96self.log.info("Transaction that spends from thin air")97bad_block = copy.deepcopy(block)98bad_tx = copy.deepcopy(bad_block.vtx[0])99bad_tx.vin[0].prevout.hash = 255100bad_block.vtx.append(bad_tx)101assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')103def non_final_transaction_test(self, node, block):104self.log.info("Non-final transaction")105bad_block = copy.deepcopy(block)106bad_block.vtx[0].nLockTime = 2**32 - 1107assert_template(node, bad_block, 'bad-txns-nonfinal')109def bad_tx_count_test(self, node, block):110self.log.info("Bad tx count")111# The tx count is immediately after the block header112bad_block_sn = bytearray(block.serialize())113assert_equal(bad_block_sn[BLOCK_HEADER_SIZE], 1)114bad_block_sn[BLOCK_HEADER_SIZE] += 1115assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {116'data': bad_block_sn.hex(),117'mode': 'proposal',118**NORMAL_GBT_REQUEST_PARAMS,119})121def nbits_test(self, node, block):122self.log.info("Extremely high nBits")123bad_block = copy.deepcopy(block)124bad_block.nBits = 469762303 # impossible in the real world125assert_template(node, bad_block, "bad-diffbits", solve=False, expect_submit="high-hash")127self.log.info("Lowering nBits should make the block invalid")128bad_block = copy.deepcopy(block)129bad_block.nBits -= 1130assert_template(node, bad_block, "bad-diffbits")132def merkle_root_test(self, node, block):133self.log.info("Bad merkle root")134bad_block = copy.deepcopy(block)135bad_block.hashMerkleRoot += 1136assert_template(node, bad_block, 'bad-txnmrklroot', rehash=False)138def bad_timestamp_test(self, node, block):139self.log.info("Bad timestamps")140bad_block = copy.deepcopy(block)141bad_block.nTime = 2**32 - 1142assert_template(node, bad_block, 'time-too-new')143bad_block.nTime = 0144assert_template(node, bad_block, 'time-too-old')146def current_tip_test(self, node, block):147self.log.info("Block must build on the current tip")148bad_block = copy.deepcopy(block)149bad_block.hashPrevBlock = 123150bad_block.solve()152assert_template(node, bad_block, "inconclusive-not-best-prevblk", expect_submit="prev-blk-not-found")154def pow_test(self, node, block):155'''Modifies block with the generated PoW'''156self.log.info("Generate a block")157target = uint256_from_compact(block.nBits)158# Ensure that it doesn't meet the target by coincidence159while block.hash_int <= target:160block.nNonce += 1161self.log.debug("Found a nonce")163self.log.info("A block template doesn't need PoW")164assert_template(node, block, None)166self.log.info("Add proof of work")167block.solve()168assert_template(node, block, None)170def submit_test(self, node, block_0_height, block):171self.log.info("getblocktemplate call in previous tests did not submit the block")172assert_equal(node.getblockcount(), block_0_height + 1)174self.log.info("Submitting this block should succeed")175assert_equal(node.submitblock(block.serialize().hex()), None)176node.waitforblockheight(2)178def transaction_test(self, node, block_0_height, tx):179self.log.info("make block template with a transaction")181block_1 = node.getblock(node.getblockhash(block_0_height + 1))182block_2_hash = node.getblockhash(block_0_height + 2)184block_3 = create_block(185int(block_2_hash, 16),186height=block_0_height + 3,187ntime=block_1["mediantime"] + 1,188txlist=[tx["hex"]],189)190assert_equal(len(block_3.vtx), 2)191add_witness_commitment(block_3)192block_3.solve()193assert_template(node, block_3, None)195self.log.info("checking block validity did not update the UTXO set")196# Call again to ensure the UTXO set wasn't updated197assert_template(node, block_3, None)199def overspending_transaction_test(self, node, block_0_height, tx):200self.log.info("Add an transaction that spends too much")202block_1 = node.getblock(node.getblockhash(block_0_height + 1))203block_2_hash = node.getblockhash(block_0_height + 2)205bad_tx = copy.deepcopy(tx)206bad_tx["tx"].vout[0].nValue = 10000000000207bad_tx_hex = bad_tx["tx"].serialize().hex()208assert_equal(209node.testmempoolaccept([bad_tx_hex])[0]["reject-reason"],210"bad-txns-in-belowout",211)212block_3 = create_block(213int(block_2_hash, 16),214height=block_0_height + 3,215ntime=block_1["mediantime"] + 1,216txlist=[bad_tx_hex],217)218assert_equal(len(block_3.vtx), 2)219add_witness_commitment(block_3)220block_3.solve()222assert_template(node, block_3, "bad-txns-in-belowout")224def spend_twice_test(self, node, block_0_height, tx):225block_1 = node.getblock(node.getblockhash(block_0_height + 1))226block_2_hash = node.getblockhash(block_0_height + 2)228self.log.info("Can't spend coins twice")229tx_hex = tx["tx"].serialize().hex()230tx_2 = copy.deepcopy(tx)231tx_2_hex = tx_2["tx"].serialize().hex()232# Nothing wrong with these transactions individually233assert_equal(node.testmempoolaccept([tx_hex])[0]["allowed"], True)234assert_equal(node.testmempoolaccept([tx_2_hex])[0]["allowed"], True)235# But can't be combined236assert_equal(237node.testmempoolaccept([tx_hex, tx_2_hex])[0]["package-error"],238"package-contains-duplicates",239)240block_3 = create_block(241int(block_2_hash, 16),242height=block_0_height + 3,243ntime=block_1["mediantime"] + 1,244txlist=[tx_hex, tx_2_hex],245)246assert_equal(len(block_3.vtx), 3)247add_witness_commitment(block_3)249assert_template(node, block_3, "bad-txns-inputs-missingorspent", submit=False)
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.