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.5"""Test mining RPCs7- getmininginfo8- getblocktemplate9- submitblock11mining_template_verification.py tests getblocktemplate in proposal mode"""13import copy14from decimal import Decimal16from test_framework.blocktools import (17create_block,18create_coinbase,19get_witness_script,20NORMAL_GBT_REQUEST_PARAMS,21TIME_GENESIS_BLOCK,22REGTEST_N_BITS,23REGTEST_TARGET,24nbits_str,25target_str,26)27from test_framework.messages import (28BLOCK_HEADER_SIZE,29CBlock,30CBlockHeader,31COIN,32DEFAULT_BLOCK_RESERVED_WEIGHT,33MAX_BLOCK_WEIGHT,34MAX_SEQUENCE_NONFINAL,35MINIMUM_BLOCK_RESERVED_WEIGHT,36ser_uint256,37WITNESS_SCALE_FACTOR,38)39from test_framework.p2p import P2PDataStore40from test_framework.test_framework import BitcoinTestFramework41from test_framework.util import (42assert_equal,43assert_greater_than,44assert_greater_than_or_equal,45assert_raises_rpc_error,46get_fee,47)48from test_framework.wallet import (49MiniWallet,50MiniWalletMode,51)54DIFFICULTY_ADJUSTMENT_INTERVAL = 14455MAX_FUTURE_BLOCK_TIME = 2 * 360056MAX_TIMEWARP = 60057VERSIONBITS_TOP_BITS = 0x2000000058VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 2859DEFAULT_BLOCK_MIN_TX_FEE = 1 # default `-blockmintxfee` setting [sat/kvB]61class MiningTest(BitcoinTestFramework):62def set_test_params(self):63self.num_nodes = 364self.extra_args = [65[],66[],67["-fastprune", "-prune=1"]68]69self.setup_clean_chain = True71def mine_chain(self):72self.log.info('Create some old blocks')73for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):74self.nodes[0].setmocktime(t)75self.generate(self.wallet, 1, sync_fun=self.no_op)76mining_info = self.nodes[0].getmininginfo()77assert_equal(mining_info['blocks'], 200)78assert_equal(mining_info['currentblocktx'], 0)79assert_equal(mining_info['currentblockweight'], DEFAULT_BLOCK_RESERVED_WEIGHT)81self.log.info('test blockversion')82self.restart_node(0, extra_args=[f'-mocktime={t}', '-blockversion=1337'])83self.connect_nodes(0, 1)84assert_equal(1337, self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['version'])85self.restart_node(0, extra_args=[f'-mocktime={t}'])86self.connect_nodes(0, 1)87assert_equal(VERSIONBITS_TOP_BITS + (1 << VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT), self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['version'])88self.restart_node(0)89self.connect_nodes(0, 1)91def test_fees_and_sigops(self):92self.log.info("Test fees and sigops in getblocktemplate result")93node = self.nodes[0]95# Generate a coinbases with p2pk transactions for its sigops.96wallet_sigops = MiniWallet(node, mode=MiniWalletMode.RAW_P2PK)97self.generate(wallet_sigops, 1, sync_fun=self.no_op)99# Mature with regular coinbases to prevent interference with other tests100self.generate(self.wallet, 100, sync_fun=self.no_op)102# Generate three transactions that must be mined in sequence103#104# tx_a (1 sat/vbyte)105# |106# |107# tx_b (2 sat/vbyte)108# |109# |110# tx_c (3 sat/vbyte)111#112tx_a = wallet_sigops.send_self_transfer(from_node=node,113fee_rate=Decimal("0.00001"))114tx_b = wallet_sigops.send_self_transfer(from_node=node,115fee_rate=Decimal("0.00002"),116utxo_to_spend=tx_a["new_utxo"])117tx_c = wallet_sigops.send_self_transfer(from_node=node,118fee_rate=Decimal("0.00003"),119utxo_to_spend=tx_b["new_utxo"])121# Generate transaction without sigops. It will go first because it pays122# higher fees (100 sat/vbyte) and descends from a different coinbase.123tx_d = self.wallet.send_self_transfer(from_node=node,124fee_rate=Decimal("0.00100"))126block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)127block_template_txs = block_template['transactions']129block_template_fees = [tx['fee'] for tx in block_template_txs]130assert_equal(block_template_fees, [131tx_d["fee"] * COIN,132tx_a["fee"] * COIN,133tx_b["fee"] * COIN,134tx_c["fee"] * COIN135])136# verify that coinbasevalue field is set to claim full block reward (subsidy + fees)137expected_block_reward = create_coinbase(138height=int(block_template["height"]), fees=sum(block_template_fees)).vout[0].nValue139assert_equal(block_template["coinbasevalue"], expected_block_reward)141block_template_sigops = [tx['sigops'] for tx in block_template_txs]142assert_equal(block_template_sigops, [0, 4, 4, 4])144# Clear mempool145self.generate(self.wallet, 1, sync_fun=self.no_op)147def test_blockmintxfee_parameter(self):148self.log.info("Test -blockmintxfee setting")149self.restart_node(0, extra_args=['-minrelaytxfee=0', '-persistmempool=0'])150node = self.nodes[0]152# test default (no parameter), zero and a bunch of arbitrary blockmintxfee rates [sat/kvB]153for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 5, 10, 50, 100, 500, 1000, 2500, 5000, 21000, 333333, 2500000):154blockmintxfee_btc_kvb = blockmintxfee_sat_kvb / Decimal(COIN)155if blockmintxfee_sat_kvb == DEFAULT_BLOCK_MIN_TX_FEE:156self.log.info(f"-> Default -blockmintxfee setting ({blockmintxfee_sat_kvb} sat/kvB)...")157else:158blockmintxfee_parameter = f"-blockmintxfee={blockmintxfee_btc_kvb:.8f}"159self.log.info(f"-> Test {blockmintxfee_parameter} ({blockmintxfee_sat_kvb} sat/kvB)...")160self.restart_node(0, extra_args=[blockmintxfee_parameter, '-minrelaytxfee=0', '-persistmempool=0'])161assert_equal(node.getmininginfo()['blockmintxfee'], blockmintxfee_btc_kvb)163# submit one tx with exactly the blockmintxfee rate, and one slightly below164tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)165assert_equal(tx_with_min_feerate["fee"], get_fee(tx_with_min_feerate["tx"].get_vsize(), blockmintxfee_btc_kvb))166if blockmintxfee_sat_kvb >= 10:167lowerfee_btc_kvb = blockmintxfee_btc_kvb - Decimal(10)/COIN # 0.01 sat/vbyte lower168assert_greater_than(blockmintxfee_btc_kvb, lowerfee_btc_kvb)169assert_greater_than_or_equal(lowerfee_btc_kvb, 0)170tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb, confirmed_only=True)171assert_equal(tx_below_min_feerate["fee"], get_fee(tx_below_min_feerate["tx"].get_vsize(), lowerfee_btc_kvb))172else: # go below zero fee by using modified fees173tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)174node.prioritisetransaction(tx_below_min_feerate["txid"], 0, -11)176# check that tx below specified fee-rate is neither in template nor in the actual block177block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)178block_template_txids = [tx['txid'] for tx in block_template['transactions']]180# Unless blockmintxfee is 0, the template shouldn't contain free transactions.181# Note that the real block assembler uses package feerates, but we didn't create dependent transactions so it's ok to use base feerate.182if blockmintxfee_btc_kvb > 0:183for txid in block_template_txids:184tx = node.getmempoolentry(txid)185assert_greater_than(tx['fees']['base'], 0)187self.generate(self.wallet, 1, sync_fun=self.no_op)188block = node.getblock(node.getbestblockhash(), verbosity=2)189block_txids = [tx['txid'] for tx in block['tx']]191assert tx_with_min_feerate['txid'] in block_template_txids192assert tx_with_min_feerate['txid'] in block_txids193assert tx_below_min_feerate['txid'] not in block_template_txids194assert tx_below_min_feerate['txid'] not in block_txids196# Restart node to clear mempool for the next test197self.restart_node(0)199def test_timewarp(self):200self.log.info("Test timewarp attack mitigation (BIP94)")201node = self.nodes[0]202self.restart_node(0, extra_args=['-test=bip94'])204self.log.info("Mine until the last block of the retarget period")205blockchain_info = self.nodes[0].getblockchaininfo()206n = DIFFICULTY_ADJUSTMENT_INTERVAL - blockchain_info['blocks'] % DIFFICULTY_ADJUSTMENT_INTERVAL - 2207t = blockchain_info['time']209for _ in range(n):210t += 600211self.nodes[0].setmocktime(t)212self.generate(self.wallet, 1, sync_fun=self.no_op)214self.log.info("Create block two hours in the future")215self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME)216self.generate(self.wallet, 1, sync_fun=self.no_op)217assert_equal(node.getblock(node.getbestblockhash())['time'], t + MAX_FUTURE_BLOCK_TIME)219self.log.info("First block template of retarget period can't use wall clock time")220self.nodes[0].setmocktime(t)221# The template will have an adjusted timestamp, which we then modify222tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)223assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP)224# mintime and curtime should match225assert_equal(tmpl['mintime'], tmpl['curtime'])227block = CBlock()228block.nVersion = tmpl["version"]229block.hashPrevBlock = int(tmpl["previousblockhash"], 16)230block.nTime = tmpl["curtime"]231block.nBits = int(tmpl["bits"], 16)232block.nNonce = 0233block.vtx = [create_coinbase(height=int(tmpl["height"]))]234block.hashMerkleRoot = block.calc_merkle_root()235block.solve()236assert_equal(node.getblocktemplate(template_request={237'data': block.serialize().hex(),238'mode': 'proposal',239**NORMAL_GBT_REQUEST_PARAMS,240}), None)242bad_block = copy.deepcopy(block)243bad_block.nTime = t244bad_block.solve()245assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))247self.log.info("Test timewarp protection boundary")248bad_block.nTime = t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP - 1249bad_block.solve()250assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))
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.