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.
501assert_raises_rpc_error(502-8,503"Block does not exist at specified height",504lambda: self.nodes[0].getnetworkhashps(100, self.nodes[0].getblockcount() + 1),505)506assert_raises_rpc_error(507-8,508"Block does not exist at specified height",509lambda: self.nodes[0].getnetworkhashps(100, -10),510)511assert_raises_rpc_error(512-8,513"Invalid nblocks. Must be a positive number or -1.",514lambda: self.nodes[0].getnetworkhashps(-100),515)516assert_raises_rpc_error(517-8,518"Invalid nblocks. Must be a positive number or -1.",519lambda: self.nodes[0].getnetworkhashps(0),520)522# Genesis block height estimate should return 0523hashes_per_second = self.nodes[0].getnetworkhashps(100, 0)524assert_equal(hashes_per_second, 0)526# This should be 2 hashes every 10 minutes or 1/300527hashes_per_second = self.nodes[0].getnetworkhashps()528assert abs(hashes_per_second * 300 - 1) < 0.0001530# Test setting the first param of getnetworkhashps to -1 returns the average network531# hashes per second from the last difficulty change.532current_block_height = self.nodes[0].getmininginfo()['blocks']533blocks_since_last_diff_change = current_block_height % DIFFICULTY_ADJUSTMENT_INTERVAL + 1534expected_hashes_per_second_since_diff_change = self.nodes[0].getnetworkhashps(blocks_since_last_diff_change)536assert_equal(self.nodes[0].getnetworkhashps(-1), expected_hashes_per_second_since_diff_change)538# Ensure long lookups get truncated to chain length539hashes_per_second = self.nodes[0].getnetworkhashps(self.nodes[0].getblockcount() + 1000)540assert hashes_per_second > 0.003542def _test_stopatheight(self):543self.log.info("Test stopping at height")544assert_equal(self.nodes[0].getblockcount(), HEIGHT)545self.generate(self.wallet, 6)546assert_equal(self.nodes[0].getblockcount(), HEIGHT + 6)547self.log.debug('Node should not stop at this height')548assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))549try:550self.generatetoaddress(self.nodes[0], 1, self.wallet.get_address(), sync_fun=self.no_op)551except (ConnectionError, http.client.BadStatusLine):552pass # The node already shut down before response553self.log.debug('Node should stop at this height...')554self.nodes[0].wait_until_stopped()555self.start_node(0)556assert_equal(self.nodes[0].getblockcount(), HEIGHT + 7)558def _test_waitforblock(self):559self.log.info("Test waitforblock and waitfornewblock")560node = self.nodes[0]562current_height = node.getblock(node.getbestblockhash())['height']563current_hash = node.getblock(node.getbestblockhash())['hash']565self.log.debug("Roll the chain back a few blocks and then reconsider it")566rollback_height = current_height - 100567rollback_hash = node.getblockhash(rollback_height)568rollback_header = node.getblockheader(rollback_hash)570node.invalidateblock(rollback_hash)571assert_equal(node.getblockcount(), rollback_height - 1)573self.log.debug("waitforblock should return the same block after its timeout")574assert_equal(node.waitforblock(blockhash=current_hash, timeout=1)['hash'], rollback_header['previousblockhash'])575assert_raises_rpc_error(-1, "Negative timeout", node.waitforblock, current_hash, -1)577node.reconsiderblock(rollback_hash)578# The chain has probably already been restored by the time reconsiderblock returns,579# but poll anyway.580self.wait_until(lambda: node.waitforblock(blockhash=current_hash, timeout=100)['hash'] == current_hash)582# roll back again583node.invalidateblock(rollback_hash)584assert_equal(node.getblockcount(), rollback_height - 1)586node.reconsiderblock(rollback_hash)587# The chain has probably already been restored by the time reconsiderblock returns,588# but poll anyway.589self.wait_until(lambda: node.waitfornewblock(current_tip=rollback_header['previousblockhash'])['hash'] == current_hash)591assert_raises_rpc_error(-1, "Negative timeout", node.waitfornewblock, -1)593def _test_waitforblockheight(self):594self.log.info("Test waitforblockheight")595node = self.nodes[0]596peer = node.add_p2p_connection(P2PInterface())598current_height = node.getblock(node.getbestblockhash())['height']600# Create a fork somewhere below our current height, invalidate the tip601# of that fork, and then ensure that waitforblockheight still602# works as expected.603#604# (Previously this was broken based on setting605# `rpc/blockchain.cpp:latestblock` incorrectly.)606#607fork_height = current_height - 100 # choose something vaguely near our tip608fork_hash = node.getblockhash(fork_height)609fork_block = node.getblock(fork_hash)611def solve_and_send_block(prevhash, height, time):612b = create_block(prevhash, height=height, ntime=time)613b.solve()614peer.send_and_ping(msg_block(b))615return b617b1 = solve_and_send_block(int(fork_hash, 16), fork_height+1, fork_block['time'] + 1)618b2 = solve_and_send_block(b1.hash_int, fork_height+2, b1.nTime + 1)620node.invalidateblock(b2.hash_hex)622def assert_waitforheight(height, timeout=2):623assert_equal(624node.waitforblockheight(height=height, timeout=timeout)['height'],625current_height)627assert_waitforheight(0)628assert_waitforheight(current_height - 1)629assert_waitforheight(current_height)630assert_waitforheight(current_height + 1)631assert_raises_rpc_error(-1, "Negative timeout", node.waitforblockheight, current_height, -1)633def _test_getblock(self):634node = self.nodes[0]635fee_per_byte = Decimal('0.00000010')636fee_per_kb = 1000 * fee_per_byte638self.wallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)639blockhash = self.generate(node, 1)[0]641def assert_coinbase_metadata(hash, verbosity):642block = node.getblock(hash, verbosity)643coinbase_tx = node.getblock(hash, 2)["tx"][0]645expected_keys = {"version", "locktime", "sequence", "coinbase"}646if "txinwitness" in coinbase_tx["vin"][0]:647expected_keys.add("witness")648assert_equal(set(block["coinbase_tx"].keys()), expected_keys)650assert_equal(block["coinbase_tx"]["version"], coinbase_tx["version"])651assert_equal(block["coinbase_tx"]["locktime"], coinbase_tx["locktime"])652assert_equal(block["coinbase_tx"]["sequence"], coinbase_tx["vin"][0]["sequence"])653assert_equal(block["coinbase_tx"]["coinbase"], coinbase_tx["vin"][0]["coinbase"])655witness_stack = coinbase_tx["vin"][0].get("txinwitness")656if witness_stack is None:657assert "witness" not in block["coinbase_tx"]658else:659assert_equal(block["coinbase_tx"]["witness"], witness_stack[0])661def assert_hexblock_hashes(verbosity):662block = node.getblock(blockhash, verbosity)663assert_equal(blockhash, hash256(bytes.fromhex(block[:160]))[::-1].hex())665def assert_fee_not_in_block(hash, verbosity):666block = node.getblock(hash, verbosity)667assert 'fee' not in block['tx'][1]669def assert_fee_in_block(hash, verbosity):670block = node.getblock(hash, verbosity)671tx = block['tx'][1]672assert 'fee' in tx673assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)675def assert_vin_contains_prevout(verbosity):676block = node.getblock(blockhash, verbosity)677tx = block["tx"][1]678total_vin = Decimal("0.00000000")679total_vout = Decimal("0.00000000")680for vin in tx["vin"]:681assert "prevout" in vin682assert_equal(set(vin["prevout"].keys()), set(("value", "height", "generated", "scriptPubKey")))683assert_equal(vin["prevout"]["generated"], True)684total_vin += vin["prevout"]["value"]685for vout in tx["vout"]:686total_vout += vout["value"]687assert_equal(total_vin, total_vout + tx["fee"])689def assert_vin_does_not_contain_prevout(hash, verbosity):690block = node.getblock(hash, verbosity)691tx = block["tx"][1]692if isinstance(tx, str):693# In verbosity level 1, only the transaction hashes are written694pass695else:696for vin in tx["vin"]:697assert "prevout" not in vin699self.log.info("Test that getblock with verbosity 0 hashes to expected value")700assert_hexblock_hashes(0)701assert_hexblock_hashes(False)703self.log.info("Test that getblock with verbosity 1 doesn't include fee")704assert_fee_not_in_block(blockhash, 1)705assert_fee_not_in_block(blockhash, True)707self.log.info("Test getblock coinbase metadata fields")708assert_coinbase_metadata(blockhash, 1)710self.log.info('Test that getblock with verbosity 2 and 3 includes expected fee')711assert_fee_in_block(blockhash, 2)712assert_fee_in_block(blockhash, 3)714self.log.info("Test that getblock with verbosity 1 and 2 does not include prevout")715assert_vin_does_not_contain_prevout(blockhash, 1)716assert_vin_does_not_contain_prevout(blockhash, 2)718self.log.info("Test that getblock with verbosity 3 includes prevout")719assert_vin_contains_prevout(3)721self.log.info("Test getblock with invalid verbosity type returns proper error message")722assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", node.getblock, blockhash, "2")724self.log.info("Test that getblock doesn't work with deleted Undo data")726def move_block_file(old, new):727old_path = self.nodes[0].blocks_path / old728new_path = self.nodes[0].blocks_path / new729old_path.rename(new_path)731# Move instead of deleting so we can restore chain state afterwards732move_block_file('rev00000.dat', 'rev_wrong')734assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 2))735assert_raises_rpc_error(-32603, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.", lambda: node.getblock(blockhash, 3))737# Restore chain state738move_block_file('rev_wrong', 'rev00000.dat')740assert 'previousblockhash' not in node.getblock(node.getblockhash(0))741assert 'nextblockhash' not in node.getblock(node.getbestblockhash())743self.log.info("Test getblock when only header is known")744current_height = node.getblock(node.getbestblockhash())['height']745block_time = node.getblock(node.getbestblockhash())['time'] + 1746block = create_block(int(blockhash, 16), create_coinbase(current_height + 1, nValue=100), ntime=block_time)747block.solve()748node.submitheader(block.serialize().hex())749assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: node.getblock(block.hash_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.