mining_mainnet.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2025 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test mining on an alternate mainnet 6 7 Test mining related RPCs that involve difficulty adjustment, which 8 regtest doesn't have. 9 10 It uses an alternate mainnet chain. See data/README.md for how it was generated. 11 12 Mine one retarget period worth of blocks with a short interval in 13 order to maximally raise the difficulty. Verify this using the getmininginfo RPC. 14 15 """ 16 17 from test_framework.test_framework import BitcoinTestFramework 18 from test_framework.util import ( 19 assert_equal, 20 ) 21 from test_framework.blocktools import ( 22 DIFF_1_N_BITS, 23 DIFF_1_TARGET, 24 DIFF_4_N_BITS, 25 DIFF_4_TARGET, 26 create_coinbase, 27 nbits_str, 28 target_str 29 ) 30 31 from test_framework.messages import ( 32 CBlock, 33 ) 34 35 import json 36 import os 37 38 # See data/README.md 39 COINBASE_SCRIPT_PUBKEY="76a914eadbac7f36c37e39361168b7aaee3cb24a25312d88ac" 40 41 class MiningMainnetTest(BitcoinTestFramework): 42 43 def set_test_params(self): 44 self.num_nodes = 1 45 self.setup_clean_chain = True 46 self.chain = "" # main 47 48 def add_options(self, parser): 49 parser.add_argument( 50 '--datafile', 51 default='data/mainnet_alt.json', 52 help='Block data file (default: %(default)s)', 53 ) 54 55 def mine(self, height, prev_hash, blocks, node, fees=0): 56 self.log.debug(f"height={height}") 57 block = CBlock() 58 block.nVersion = 0x20000000 59 block.hashPrevBlock = int(prev_hash, 16) 60 block.nTime = blocks['timestamps'][height - 1] 61 block.nBits = DIFF_1_N_BITS 62 block.nNonce = blocks['nonces'][height - 1] 63 block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), retarget_period=2016)] 64 block.hashMerkleRoot = block.calc_merkle_root() 65 block.rehash() 66 block_hex = block.serialize(with_witness=False).hex() 67 self.log.debug(block_hex) 68 assert_equal(node.submitblock(block_hex), None) 69 prev_hash = node.getbestblockhash() 70 assert_equal(prev_hash, block.hash) 71 return prev_hash 72 73 74 def run_test(self): 75 node = self.nodes[0] 76 # Clear disk space warning 77 node.stderr.seek(0) 78 node.stderr.truncate() 79 self.log.info("Load alternative mainnet blocks") 80 path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile) 81 prev_hash = node.getbestblockhash() 82 with open(path, encoding='utf-8') as f: 83 blocks = json.load(f) 84 n_blocks = len(blocks['timestamps']) 85 assert_equal(n_blocks, 2015) 86 for i in range(2015): 87 prev_hash = self.mine(i + 1, prev_hash, blocks, node) 88 89 assert_equal(node.getblockcount(), 2015) 90 91 self.log.info("Check difficulty adjustment with getmininginfo") 92 mining_info = node.getmininginfo() 93 assert_equal(mining_info['difficulty'], 1) 94 assert_equal(mining_info['bits'], nbits_str(DIFF_1_N_BITS)) 95 assert_equal(mining_info['target'], target_str(DIFF_1_TARGET)) 96 97 assert_equal(mining_info['next']['height'], 2016) 98 assert_equal(mining_info['next']['difficulty'], 4) 99 assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS)) 100 assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET)) 101 102 if __name__ == '__main__': 103 MiningMainnetTest(__file__).main()