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# Note: continues past -stopatheight height, so must be invoked252# after _test_stopatheight254self.log.info("Test getdeploymentinfo")255self.stop_node(0)256self.start_node(0, extra_args=[257'-testactivationheight=bip34@2',258'-testactivationheight=dersig@3',259'-testactivationheight=cltv@4',260'-testactivationheight=csv@5',261'-testactivationheight=segwit@6',262])264gbci207 = self.nodes[0].getblockchaininfo()265self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(), gbci207["blocks"], gbci207["bestblockhash"], "started")267# block just prior to lock in268self.generate(self.wallet, 287 - gbci207["blocks"])269gbci287 = self.nodes[0].getblockchaininfo()270self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(), gbci287["blocks"], gbci287["bestblockhash"], "locked_in")272# calling with an explicit hash works273self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(gbci207["bestblockhash"]), gbci207["blocks"], gbci207["bestblockhash"], "started")275def _test_verificationprogress(self):276self.log.info("Check that verificationprogress is less than 1 when the block tip is old")277future = 2 * 60 * 60278self.nodes[0].setmocktime(self.nodes[0].getblockchaininfo()["time"] + future + 1)279assert_greater_than(1, self.nodes[0].getblockchaininfo()["verificationprogress"])281self.log.info("Check that verificationprogress is exactly 1 for a recent block tip")282self.nodes[0].setmocktime(self.nodes[0].getblockchaininfo()["time"] + future)283assert_equal(1, self.nodes[0].getblockchaininfo()["verificationprogress"])285self.log.info("Check that verificationprogress is less than 1 as soon as a new header comes in")286self.nodes[0].submitheader(self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False, sync_fun=self.no_op)["hex"])287assert_greater_than(1, self.nodes[0].getblockchaininfo()["verificationprogress"])289def _test_y2106(self):290self.log.info("Check that block timestamps work until year 2106")291self.generate(self.nodes[0], 8)[-1]292time_2106 = 2**32 - 1293assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not -1.", self.nodes[0].setmocktime, -1)294assert_raises_rpc_error(-8, f"Mocktime must be in the range [0, {time_2106}], not {time_2106 + 1}.", self.nodes[0].setmocktime, time_2106 + 1)295self.nodes[0].setmocktime(time_2106)296last = self.generate(self.nodes[0], 6)[-1]297assert_equal(self.nodes[0].getblockheader(last)["mediantime"], time_2106)299def _test_getchaintxstats(self):300self.log.info("Test getchaintxstats")302# Test `getchaintxstats` invalid extra parameters303assert_raises_rpc_error(-1, 'getchaintxstats', self.nodes[0].getchaintxstats, 0, '', 0)305# Test `getchaintxstats` invalid `nblocks`306assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].getchaintxstats, '')307assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, -1)308assert_raises_rpc_error(-8, "Invalid block count: should be between 0 and the block's height - 1", self.nodes[0].getchaintxstats, self.nodes[0].getblockcount())310# Test `getchaintxstats` invalid `blockhash`311assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].getchaintxstats, blockhash=0)312assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 1, for '0')", self.nodes[0].getchaintxstats, blockhash='0')313assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000')314assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000')315blockhash = self.nodes[0].getblockhash(HEIGHT)316self.nodes[0].invalidateblock(blockhash)317assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash)318self.nodes[0].reconsiderblock(blockhash)320chaintxstats = self.nodes[0].getchaintxstats(nblocks=1)321# 200 txs plus genesis tx322assert_equal(chaintxstats['txcount'], HEIGHT + 1)323# tx rate should be 1 per 10 minutes, or 1/600324# we have to round because of binary math325assert_equal(round(chaintxstats['txrate'] * TIME_RANGE_STEP, 10), Decimal(1))327b1_hash = self.nodes[0].getblockhash(1)328b1 = self.nodes[0].getblock(b1_hash)329b200_hash = self.nodes[0].getblockhash(HEIGHT)330b200 = self.nodes[0].getblock(b200_hash)331time_diff = b200['mediantime'] - b1['mediantime']333chaintxstats = self.nodes[0].getchaintxstats()334assert_equal(chaintxstats['time'], b200['time'])335assert_equal(chaintxstats['txcount'], HEIGHT + 1)336assert_equal(chaintxstats['window_final_block_hash'], b200_hash)337assert_equal(chaintxstats['window_final_block_height'], HEIGHT )338assert_equal(chaintxstats['window_block_count'], HEIGHT - 1)339assert_equal(chaintxstats['window_tx_count'], HEIGHT - 1)340assert_equal(chaintxstats['window_interval'], time_diff)341assert_equal(round(chaintxstats['txrate'] * time_diff, 10), Decimal(HEIGHT - 1))343chaintxstats = self.nodes[0].getchaintxstats(blockhash=b1_hash)344assert_equal(chaintxstats['time'], b1['time'])345assert_equal(chaintxstats['txcount'], 2)346assert_equal(chaintxstats['window_final_block_hash'], b1_hash)347assert_equal(chaintxstats['window_final_block_height'], 1)348assert_equal(chaintxstats['window_block_count'], 0)349assert 'window_tx_count' not in chaintxstats350assert 'window_interval' not in chaintxstats351assert 'txrate' not in chaintxstats353def _test_gettxoutsetinfo(self):354node = self.nodes[0]355res = node.gettxoutsetinfo()357assert_equal(res['total_amount'], Decimal('8725.00000000'))358assert_equal(res['transactions'], HEIGHT)359assert_equal(res['height'], HEIGHT)360assert_equal(res['txouts'], HEIGHT)361assert_equal(res['bogosize'], 16800),362assert_equal(res['bestblock'], node.getblockhash(HEIGHT))363size = res['disk_size']364assert size > 6400365assert size < 64000366assert_equal(len(res['bestblock']), 64)367assert_equal(len(res['hash_serialized_3']), 64)369self.log.info("Test gettxoutsetinfo works for blockchain with just the genesis block")370b1hash = node.getblockhash(1)371node.invalidateblock(b1hash)373res2 = node.gettxoutsetinfo()374assert_equal(res2['transactions'], 0)375assert_equal(res2['total_amount'], Decimal('0'))376assert_equal(res2['height'], 0)377assert_equal(res2['txouts'], 0)378assert_equal(res2['bogosize'], 0),379assert_equal(res2['bestblock'], node.getblockhash(0))380assert_equal(len(res2['hash_serialized_3']), 64)382self.log.info("Test gettxoutsetinfo returns the same result after invalidate/reconsider block")383node.reconsiderblock(b1hash)385res3 = node.gettxoutsetinfo()386# The field 'disk_size' is non-deterministic and can thus not be387# compared between res and res3. Everything else should be the same.388del res['disk_size'], res3['disk_size']389assert_equal(res, res3)391self.log.info("Test gettxoutsetinfo hash_type option")392# Adding hash_type 'hash_serialized_3', which is the default, should393# not change the result.394res4 = node.gettxoutsetinfo(hash_type='hash_serialized_3')395del res4['disk_size']396assert_equal(res, res4)398# hash_type none should not return a UTXO set hash.399res5 = node.gettxoutsetinfo(hash_type='none')400assert 'hash_serialized_3' not in res5402# hash_type muhash should return a different UTXO set hash.403res6 = node.gettxoutsetinfo(hash_type='muhash')404assert 'muhash' in res6405assert_not_equal(res['hash_serialized_3'], res6['muhash'])407# muhash should not be returned unless requested.408for r in [res, res2, res3, res4, res5]:409assert 'muhash' not in r411# Unknown hash_type raises an error412assert_raises_rpc_error(-8, "'foo hash' is not a valid hash_type", node.gettxoutsetinfo, "foo hash")414def _test_gettxout(self):415self.log.info("Validating gettxout RPC response")416node = self.nodes[0]418# Get the best block hash and the block, which419# should only include the coinbase transaction.420best_block_hash = node.getbestblockhash()421block = node.getblock(best_block_hash)422assert_equal(block['nTx'], 1)424# Get the transaction ID of the coinbase tx and425# the transaction output.426txid = block['tx'][0]427txout = node.gettxout(txid, 0)429# Validate the gettxout response430assert_equal(txout['bestblock'], best_block_hash)431assert_equal(txout['confirmations'], 1)432assert_equal(txout['value'], 25)433assert_equal(txout['scriptPubKey']['address'], self.wallet.get_address())434assert_equal(txout['scriptPubKey']['hex'], self.wallet.get_output_script().hex())435decoded_script = node.decodescript(self.wallet.get_output_script().hex())436assert_equal(txout['scriptPubKey']['asm'], decoded_script['asm'])437assert_equal(txout['scriptPubKey']['desc'], decoded_script['desc'])438assert_equal(txout['scriptPubKey']['type'], decoded_script['type'])439assert_equal(txout['coinbase'], True)441def _test_getblockheader(self):442self.log.info("Test getblockheader")443node = self.nodes[0]445assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense")446assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")447assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")449besthash = node.getbestblockhash()450secondbesthash = node.getblockhash(HEIGHT - 1)451header = node.getblockheader(blockhash=besthash)453assert_equal(header['hash'], besthash)454assert_equal(header['height'], HEIGHT)455assert_equal(header['confirmations'], 1)456assert_equal(header['previousblockhash'], secondbesthash)457assert_is_hex_string(header['chainwork'])458assert_equal(header['nTx'], 1)459assert_is_hash_string(header['hash'])460assert_is_hash_string(header['previousblockhash'])461assert_is_hash_string(header['merkleroot'])462assert_equal(header['bits'], nbits_str(REGTEST_N_BITS))463assert_equal(header['target'], target_str(REGTEST_TARGET))464assert isinstance(header['time'], int)465assert_equal(header['mediantime'], TIME_RANGE_MTP)466assert isinstance(header['nonce'], int)467assert isinstance(header['version'], int)468assert isinstance(int(header['versionHex'], 16), int)469assert isinstance(header['difficulty'], Decimal)471# Test with verbose=False, which should return the header as hex.472header_hex = node.getblockheader(blockhash=besthash, verbose=False)473assert_is_hex_string(header_hex)475header = from_hex(CBlockHeader(), header_hex)476assert_equal(header.hash_hex, besthash)478assert 'previousblockhash' not in node.getblockheader(node.getblockhash(0))479assert 'nextblockhash' not in node.getblockheader(node.getbestblockhash())481def _test_getdifficulty(self):482self.log.info("Test getdifficulty")483difficulty = self.nodes[0].getdifficulty()484# 1 hash in 2 should be valid, so difficulty should be 1/2**31485# binary => decimal => binary math is why we do this check486assert abs(difficulty * 2**31 - 1) < 0.0001488def _test_getnetworkhashps(self):489self.log.info("Test getnetworkhashps")490assert_raises_rpc_error(491-3,492textwrap.dedent("""493Wrong type passed:494{495"Position 1 (nblocks)": "JSON value of type string is not of expected type number",496"Position 2 (height)": "JSON value of type array is not of expected type number"497}498""").strip(),499lambda: self.nodes[0].getnetworkhashps("a", []),500)
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.