mining_basic.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2014-present 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 RPCs
   6  
   7  - getmininginfo
   8  - getblocktemplate
   9  - submitblock
  10  
  11  mining_template_verification.py tests getblocktemplate in proposal mode"""
  12  
  13  import copy
  14  from decimal import Decimal
  15  
  16  from test_framework.blocktools import (
  17      create_coinbase,
  18      get_witness_script,
  19      NORMAL_GBT_REQUEST_PARAMS,
  20      TIME_GENESIS_BLOCK,
  21      REGTEST_N_BITS,
  22      REGTEST_TARGET,
  23      nbits_str,
  24      target_str,
  25  )
  26  from test_framework.messages import (
  27      BLOCK_HEADER_SIZE,
  28      CBlock,
  29      CBlockHeader,
  30      COIN,
  31      DEFAULT_BLOCK_RESERVED_WEIGHT,
  32      MAX_BLOCK_WEIGHT,
  33      MAX_SEQUENCE_NONFINAL,
  34      MINIMUM_BLOCK_RESERVED_WEIGHT,
  35      ser_uint256,
  36      WITNESS_SCALE_FACTOR,
  37  )
  38  from test_framework.p2p import P2PDataStore
  39  from test_framework.test_framework import BitcoinTestFramework
  40  from test_framework.util import (
  41      assert_equal,
  42      assert_greater_than,
  43      assert_greater_than_or_equal,
  44      assert_raises_rpc_error,
  45      get_fee,
  46  )
  47  from test_framework.wallet import (
  48      MiniWallet,
  49      MiniWalletMode,
  50  )
  51  
  52  
  53  DIFFICULTY_ADJUSTMENT_INTERVAL = 144
  54  MAX_FUTURE_BLOCK_TIME = 2 * 3600
  55  MAX_TIMEWARP = 600
  56  VERSIONBITS_TOP_BITS = 0x20000000
  57  VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
  58  DEFAULT_BLOCK_MIN_TX_FEE = 1 # default `-blockmintxfee` setting [sat/kvB]
  59  
  60  class MiningTest(BitcoinTestFramework):
  61      def set_test_params(self):
  62          self.num_nodes = 3
  63          self.extra_args = [
  64              [],
  65              [],
  66              ["-fastprune", "-prune=1"]
  67          ]
  68          self.setup_clean_chain = True
  69  
  70      def mine_chain(self):
  71          self.log.info('Create some old blocks')
  72          for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
  73              self.nodes[0].setmocktime(t)
  74              self.generate(self.wallet, 1, sync_fun=self.no_op)
  75          mining_info = self.nodes[0].getmininginfo()
  76          assert_equal(mining_info['blocks'], 200)
  77          assert_equal(mining_info['currentblocktx'], 0)
  78          assert_equal(mining_info['currentblockweight'], DEFAULT_BLOCK_RESERVED_WEIGHT)
  79  
  80          self.log.info('test blockversion')
  81          self.restart_node(0, extra_args=[f'-mocktime={t}', '-blockversion=1337'])
  82          self.connect_nodes(0, 1)
  83          assert_equal(1337, self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['version'])
  84          self.restart_node(0, extra_args=[f'-mocktime={t}'])
  85          self.connect_nodes(0, 1)
  86          assert_equal(VERSIONBITS_TOP_BITS + (1 << VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT), self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['version'])
  87          self.restart_node(0)
  88          self.connect_nodes(0, 1)
  89  
  90      def test_fees_and_sigops(self):
  91          self.log.info("Test fees and sigops in getblocktemplate result")
  92          node = self.nodes[0]
  93  
  94          # Generate a coinbases with p2pk transactions for its sigops.
  95          wallet_sigops = MiniWallet(node, mode=MiniWalletMode.RAW_P2PK)
  96          self.generate(wallet_sigops, 1, sync_fun=self.no_op)
  97  
  98          # Mature with regular coinbases to prevent interference with other tests
  99          self.generate(self.wallet, 100, sync_fun=self.no_op)
 100  
 101          # Generate three transactions that must be mined in sequence
 102          #
 103          #      tx_a (1 sat/vbyte)
 104          #        |
 105          #        |
 106          #      tx_b (2 sat/vbyte)
 107          #        |
 108          #        |
 109          #      tx_c (3 sat/vbyte)
 110          #
 111          tx_a = wallet_sigops.send_self_transfer(from_node=node,
 112                                                  fee_rate=Decimal("0.00001"))
 113          tx_b = wallet_sigops.send_self_transfer(from_node=node,
 114                                                  fee_rate=Decimal("0.00002"),
 115                                                  utxo_to_spend=tx_a["new_utxo"])
 116          tx_c = wallet_sigops.send_self_transfer(from_node=node,
 117                                                  fee_rate=Decimal("0.00003"),
 118                                                  utxo_to_spend=tx_b["new_utxo"])
 119  
 120          # Generate transaction without sigops. It will go first because it pays
 121          # higher fees (100 sat/vbyte) and descends from a different coinbase.
 122          tx_d = self.wallet.send_self_transfer(from_node=node,
 123                                                fee_rate=Decimal("0.00100"))
 124  
 125          block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 126          block_template_txs = block_template['transactions']
 127  
 128          block_template_fees = [tx['fee'] for tx in block_template_txs]
 129          assert_equal(block_template_fees, [
 130              tx_d["fee"] * COIN,
 131              tx_a["fee"] * COIN,
 132              tx_b["fee"] * COIN,
 133              tx_c["fee"] * COIN
 134          ])
 135          # verify that coinbasevalue field is set to claim full block reward (subsidy + fees)
 136          expected_block_reward = create_coinbase(
 137              height=int(block_template["height"]), fees=sum(block_template_fees)).vout[0].nValue
 138          assert_equal(block_template["coinbasevalue"], expected_block_reward)
 139  
 140          block_template_sigops = [tx['sigops'] for tx in block_template_txs]
 141          assert_equal(block_template_sigops, [0, 4, 4, 4])
 142  
 143          # Clear mempool
 144          self.generate(self.wallet, 1, sync_fun=self.no_op)
 145  
 146      def test_blockmintxfee_parameter(self):
 147          self.log.info("Test -blockmintxfee setting")
 148          self.restart_node(0, extra_args=['-minrelaytxfee=0', '-persistmempool=0'])
 149          node = self.nodes[0]
 150  
 151          # test default (no parameter), zero and a bunch of arbitrary blockmintxfee rates [sat/kvB]
 152          for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 5, 10, 50, 100, 500, 1000, 2500, 5000, 21000, 333333, 2500000):
 153              blockmintxfee_btc_kvb = blockmintxfee_sat_kvb / Decimal(COIN)
 154              if blockmintxfee_sat_kvb == DEFAULT_BLOCK_MIN_TX_FEE:
 155                  self.log.info(f"-> Default -blockmintxfee setting ({blockmintxfee_sat_kvb} sat/kvB)...")
 156              else:
 157                  blockmintxfee_parameter = f"-blockmintxfee={blockmintxfee_btc_kvb:.8f}"
 158                  self.log.info(f"-> Test {blockmintxfee_parameter} ({blockmintxfee_sat_kvb} sat/kvB)...")
 159                  self.restart_node(0, extra_args=[blockmintxfee_parameter, '-minrelaytxfee=0', '-persistmempool=0'])
 160              assert_equal(node.getmininginfo()['blockmintxfee'], blockmintxfee_btc_kvb)
 161  
 162              # submit one tx with exactly the blockmintxfee rate, and one slightly below
 163              tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)
 164              assert_equal(tx_with_min_feerate["fee"], get_fee(tx_with_min_feerate["tx"].get_vsize(), blockmintxfee_btc_kvb))
 165              if blockmintxfee_sat_kvb >= 10:
 166                  lowerfee_btc_kvb = blockmintxfee_btc_kvb - Decimal(10)/COIN  # 0.01 sat/vbyte lower
 167                  assert_greater_than(blockmintxfee_btc_kvb, lowerfee_btc_kvb)
 168                  assert_greater_than_or_equal(lowerfee_btc_kvb, 0)
 169                  tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb, confirmed_only=True)
 170                  assert_equal(tx_below_min_feerate["fee"], get_fee(tx_below_min_feerate["tx"].get_vsize(), lowerfee_btc_kvb))
 171              else:  # go below zero fee by using modified fees
 172                  tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)
 173                  node.prioritisetransaction(tx_below_min_feerate["txid"], 0, -11)
 174  
 175              # check that tx below specified fee-rate is neither in template nor in the actual block
 176              block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 177              block_template_txids = [tx['txid'] for tx in block_template['transactions']]
 178  
 179              # Unless blockmintxfee is 0, the template shouldn't contain free transactions.
 180              # Note that the real block assembler uses package feerates, but we didn't create dependent transactions so it's ok to use base feerate.
 181              if blockmintxfee_btc_kvb > 0:
 182                  for txid in block_template_txids:
 183                      tx = node.getmempoolentry(txid)
 184                      assert_greater_than(tx['fees']['base'], 0)
 185  
 186              self.generate(self.wallet, 1, sync_fun=self.no_op)
 187              block = node.getblock(node.getbestblockhash(), verbosity=2)
 188              block_txids = [tx['txid'] for tx in block['tx']]
 189  
 190              assert tx_with_min_feerate['txid'] in block_template_txids
 191              assert tx_with_min_feerate['txid'] in block_txids
 192              assert tx_below_min_feerate['txid'] not in block_template_txids
 193              assert tx_below_min_feerate['txid'] not in block_txids
 194  
 195              # Restart node to clear mempool for the next test
 196              self.restart_node(0)
 197  
 198      def test_timewarp(self):
 199          self.log.info("Test timewarp attack mitigation (BIP94)")
 200          node = self.nodes[0]
 201          self.restart_node(0, extra_args=['-test=bip94'])
 202  
 203          self.log.info("Mine until the last block of the retarget period")
 204          blockchain_info = self.nodes[0].getblockchaininfo()
 205          n = DIFFICULTY_ADJUSTMENT_INTERVAL - blockchain_info['blocks'] % DIFFICULTY_ADJUSTMENT_INTERVAL - 2
 206          t = blockchain_info['time']
 207  
 208          for _ in range(n):
 209              t += 600
 210              self.nodes[0].setmocktime(t)
 211              self.generate(self.wallet, 1, sync_fun=self.no_op)
 212  
 213          self.log.info("Create block two hours in the future")
 214          self.nodes[0].setmocktime(t + MAX_FUTURE_BLOCK_TIME)
 215          self.generate(self.wallet, 1, sync_fun=self.no_op)
 216          assert_equal(node.getblock(node.getbestblockhash())['time'], t + MAX_FUTURE_BLOCK_TIME)
 217  
 218          self.log.info("First block template of retarget period can't use wall clock time")
 219          self.nodes[0].setmocktime(t)
 220          # The template will have an adjusted timestamp, which we then modify
 221          tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 222          assert_greater_than_or_equal(tmpl['curtime'], t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP)
 223          # mintime and curtime should match
 224          assert_equal(tmpl['mintime'], tmpl['curtime'])
 225  
 226          block = CBlock()
 227          block.nVersion = tmpl["version"]
 228          block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
 229          block.nTime = tmpl["curtime"]
 230          block.nBits = int(tmpl["bits"], 16)
 231          block.nNonce = 0
 232          block.vtx = [create_coinbase(height=int(tmpl["height"]))]
 233          block.hashMerkleRoot = block.calc_merkle_root()
 234          block.solve()
 235          assert_equal(node.getblocktemplate(template_request={
 236              'data': block.serialize().hex(),
 237              'mode': 'proposal',
 238              **NORMAL_GBT_REQUEST_PARAMS,
 239          }), None)
 240  
 241          bad_block = copy.deepcopy(block)
 242          bad_block.nTime = t
 243          bad_block.solve()
 244          assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))
 245  
 246          self.log.info("Test timewarp protection boundary")
 247          bad_block.nTime = t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP - 1
 248          bad_block.solve()
 249          assert_raises_rpc_error(-25, 'time-timewarp-attack', lambda: node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex()))
 250  
 251          bad_block.nTime = t + MAX_FUTURE_BLOCK_TIME - MAX_TIMEWARP
 252          bad_block.solve()
 253          node.submitheader(hexdata=CBlockHeader(bad_block).serialize().hex())
 254  
 255      def test_pruning(self):
 256          self.log.info("Test that submitblock stores previously pruned block")
 257          prune_node = self.nodes[2]
 258          self.generate(prune_node, 400, sync_fun=self.no_op)
 259          pruned_block = prune_node.getblock(prune_node.getblockhash(2), verbosity=0)
 260          pruned_height = prune_node.pruneblockchain(400)
 261          assert_greater_than_or_equal(pruned_height, 2)
 262          pruned_blockhash = prune_node.getblockhash(2)
 263  
 264          assert_raises_rpc_error(-1, 'Block not available (pruned data)', prune_node.getblock, pruned_blockhash)
 265  
 266          result = prune_node.submitblock(pruned_block)
 267          assert_equal(result, "inconclusive")
 268          assert_equal(prune_node.getblock(pruned_blockhash, verbosity=0), pruned_block)
 269  
 270  
 271      def send_transactions(self, utxos, fee_rate, target_vsize):
 272          """
 273          Helper to create and send transactions with the specified target virtual size and fee rate.
 274          """
 275          for utxo in utxos:
 276              self.wallet.send_self_transfer(
 277                  from_node=self.nodes[0],
 278                  utxo_to_spend=utxo,
 279                  target_vsize=target_vsize,
 280                  fee_rate=fee_rate,
 281              )
 282  
 283      def verify_block_template(self, expected_tx_count, expected_weight):
 284          """
 285          Create a block template and check that it satisfies the expected transaction count and total weight.
 286          """
 287          response = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 288          self.log.info(f"Testing block template: contains {expected_tx_count} transactions, and total weight <= {expected_weight}")
 289          assert_equal(len(response["transactions"]), expected_tx_count)
 290          total_weight = sum(transaction["weight"] for transaction in response["transactions"])
 291          assert_greater_than_or_equal(expected_weight, total_weight)
 292  
 293      def test_block_max_weight(self):
 294          self.log.info("Testing default and custom -blockmaxweight startup options.")
 295  
 296          LARGE_TXS_COUNT = 10
 297          LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT)
 298          HIGH_FEERATE = Decimal("0.0003")
 299  
 300          # Ensure the mempool is empty
 301          assert_equal(len(self.nodes[0].getrawmempool()), 0)
 302  
 303          # Generate UTXOs and send 10 large transactions with a high fee rate
 304          utxos = [self.wallet.get_utxo(confirmed_only=True) for _ in range(LARGE_TXS_COUNT + 4)] # Add 4 more utxos that will be used in the test later
 305          self.send_transactions(utxos[:LARGE_TXS_COUNT], HIGH_FEERATE, LARGE_VSIZE)
 306  
 307          # Send 2 normal transactions with a lower fee rate
 308          NORMAL_VSIZE = int(2000 / WITNESS_SCALE_FACTOR)
 309          NORMAL_FEERATE = Decimal("0.0001")
 310          self.send_transactions(utxos[LARGE_TXS_COUNT:LARGE_TXS_COUNT + 2], NORMAL_FEERATE, NORMAL_VSIZE)
 311  
 312          # Check that the mempool contains all transactions
 313          self.log.info(f"Testing that the mempool contains {LARGE_TXS_COUNT + 2} transactions.")
 314          assert_equal(len(self.nodes[0].getrawmempool()), LARGE_TXS_COUNT + 2)
 315  
 316          # Verify the block template includes only the 10 high-fee transactions
 317          self.log.info("Testing that the block template includes only the 10 large transactions.")
 318          self.verify_block_template(
 319              expected_tx_count=LARGE_TXS_COUNT,
 320              expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT,
 321          )
 322  
 323          # Test block template creation with custom -blockmaxweight
 324          custom_block_weight = MAX_BLOCK_WEIGHT - 2000
 325          # Reducing the weight by 2000 units will prevent 1 large transaction from fitting into the block.
 326          self.restart_node(0, extra_args=[f"-blockmaxweight={custom_block_weight}"])
 327  
 328          self.log.info("Testing the block template with custom -blockmaxweight to include 9 large and 2 normal transactions.")
 329          self.verify_block_template(
 330              expected_tx_count=11,
 331              expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT - 2000,
 332          )
 333  
 334          # Ensure the block weight does not exceed the maximum
 335          self.log.info(f"Testing that the block weight will never exceed {MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT}.")
 336          self.restart_node(0, extra_args=[f"-blockmaxweight={MAX_BLOCK_WEIGHT}"])
 337          self.log.info("Sending 2 additional normal transactions to fill the mempool to the maximum block weight.")
 338          self.send_transactions(utxos[LARGE_TXS_COUNT + 2:], NORMAL_FEERATE, NORMAL_VSIZE)
 339          self.log.info(f"Testing that the mempool's weight matches the maximum block weight: {MAX_BLOCK_WEIGHT}.")
 340          assert_equal(self.nodes[0].getmempoolinfo()['bytes'] * WITNESS_SCALE_FACTOR, MAX_BLOCK_WEIGHT)
 341  
 342          self.log.info("Testing that the block template includes only 10 transactions and cannot reach full block weight.")
 343          self.verify_block_template(
 344              expected_tx_count=LARGE_TXS_COUNT,
 345              expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT,
 346          )
 347  
 348          self.log.info("Test -blockreservedweight startup option.")
 349          # Lowering the -blockreservedweight by 4000 will allow for two more transactions.
 350          self.restart_node(0, extra_args=["-blockreservedweight=4000"])
 351          self.verify_block_template(
 352              expected_tx_count=12,
 353              expected_weight=MAX_BLOCK_WEIGHT - 4000,
 354          )
 355  
 356          self.log.info("Test that node will fail to start when user provide invalid -blockreservedweight")
 357          self.stop_node(0)
 358          self.nodes[0].assert_start_raises_init_error(
 359              extra_args=[f"-blockreservedweight={MAX_BLOCK_WEIGHT + 1}"],
 360              expected_msg=f"Error: -blockreservedweight ({MAX_BLOCK_WEIGHT + 1}) exceeds consensus maximum block weight ({MAX_BLOCK_WEIGHT})",
 361          )
 362  
 363          self.log.info(f"Test that node will fail to start when user provide -blockreservedweight below {MINIMUM_BLOCK_RESERVED_WEIGHT}")
 364          self.stop_node(0)
 365          self.nodes[0].assert_start_raises_init_error(
 366              extra_args=[f"-blockreservedweight={MINIMUM_BLOCK_RESERVED_WEIGHT - 1}"],
 367              expected_msg=f"Error: -blockreservedweight ({MINIMUM_BLOCK_RESERVED_WEIGHT - 1}) is lower than minimum safety value of ({MINIMUM_BLOCK_RESERVED_WEIGHT})",
 368          )
 369  
 370          self.log.info("Test that node will fail to start when user provide invalid -blockmaxweight")
 371          self.stop_node(0)
 372          self.nodes[0].assert_start_raises_init_error(
 373              extra_args=[f"-blockmaxweight={MAX_BLOCK_WEIGHT + 1}"],
 374              expected_msg=f"Error: -blockmaxweight ({MAX_BLOCK_WEIGHT + 1}) exceeds consensus maximum block weight ({MAX_BLOCK_WEIGHT})",
 375          )
 376  
 377          self.log.info("Test that node will fail to start when -blockmaxweight is lower than -blockreservedweight")
 378          self.stop_node(0)
 379          self.nodes[0].assert_start_raises_init_error(
 380              extra_args=[f"-blockmaxweight={DEFAULT_BLOCK_RESERVED_WEIGHT - 1}"],
 381              expected_msg=f"Error: -blockreservedweight ({DEFAULT_BLOCK_RESERVED_WEIGHT}) exceeds -blockmaxweight ({DEFAULT_BLOCK_RESERVED_WEIGHT - 1})",
 382          )
 383  
 384      def test_height_in_locktime(self):
 385          self.log.info("Sanity check generated blocks have their coinbase timelocked to their height.")
 386          self.generate(self.nodes[0], 1, sync_fun=self.no_op)
 387          block = self.nodes[0].getblock(self.nodes[0].getbestblockhash(), 2)
 388          assert_equal(block["tx"][0]["locktime"], block["height"] - 1)
 389          assert_equal(block["tx"][0]["vin"][0]["sequence"], MAX_SEQUENCE_NONFINAL)
 390  
 391      def run_test(self):
 392          node = self.nodes[0]
 393          self.wallet = MiniWallet(node)
 394          self.mine_chain()
 395  
 396          self.log.info('getmininginfo')
 397          mining_info = node.getmininginfo()
 398          assert_equal(mining_info['blocks'], 200)
 399          assert_equal(mining_info['chain'], self.chain)
 400          assert 'currentblocktx' not in mining_info
 401          assert 'currentblockweight' not in mining_info
 402          assert_equal(mining_info['bits'], nbits_str(REGTEST_N_BITS))
 403          assert_equal(mining_info['target'], target_str(REGTEST_TARGET))
 404          # We don't care about precision, round to avoid mismatch under Valgrind:
 405          assert_equal(round(mining_info['difficulty'], 10), Decimal('0.0000000005'))
 406          assert_equal(mining_info['next']['height'], 201)
 407          assert_equal(mining_info['next']['target'], target_str(REGTEST_TARGET))
 408          assert_equal(mining_info['next']['bits'], nbits_str(REGTEST_N_BITS))
 409          assert_equal(round(mining_info['next']['difficulty'], 10), Decimal('0.0000000005'))
 410          assert_equal(round(mining_info['networkhashps'], 5), Decimal('0.00333'))
 411          assert_equal(mining_info['pooledtx'], 0)
 412  
 413          self.log.info("getblocktemplate: Test default witness commitment")
 414          txid = int(self.wallet.send_self_transfer(from_node=node)['wtxid'], 16)
 415          tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 416  
 417          # Check that default_witness_commitment is present.
 418          assert 'default_witness_commitment' in tmpl
 419          witness_commitment = tmpl['default_witness_commitment']
 420  
 421          # Check that default_witness_commitment is correct.
 422          witness_root = CBlock.get_merkle_root([ser_uint256(0),
 423                                                 ser_uint256(txid)])
 424          script = get_witness_script(witness_root, 0)
 425          assert_equal(witness_commitment, script.hex())
 426  
 427          # Mine a block to leave initial block download and clear the mempool
 428          self.generatetoaddress(node, 1, node.get_deterministic_priv_key().address)
 429          tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
 430          self.log.info("getblocktemplate: Test capability advertised")
 431          assert 'proposal' in tmpl['capabilities']
 432          assert 'coinbasetxn' not in tmpl
 433  
 434          next_height = int(tmpl["height"])
 435          coinbase_tx = create_coinbase(height=next_height)
 436          # sequence numbers must not be max for nLockTime to have effect
 437          coinbase_tx.vin[0].nSequence = 2**32 - 2
 438  
 439          block = CBlock()
 440          block.nVersion = tmpl["version"]
 441          block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
 442          block.nTime = tmpl["curtime"]
 443          block.nBits = int(tmpl["bits"], 16)
 444          block.nNonce = 0
 445          block.vtx = [coinbase_tx]
 446          block.hashMerkleRoot = block.calc_merkle_root()
 447  
 448          self.log.info("getblocktemplate: segwit rule must be set")
 449          assert_raises_rpc_error(-8, "getblocktemplate must be called with the segwit rule set", node.getblocktemplate, {})
 450  
 451          self.log.info("getblocktemplate: result should set the right rules")
 452          assert_equal(['csv', '!segwit', 'taproot'], self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['rules'])
 453  
 454          self.log.info("submitblock: Test block decode failure")
 455          assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, block.serialize()[:-15].hex())
 456  
 457          self.log.info("submitblock: Test empty block")
 458          assert_equal('high-hash', node.submitblock(hexdata=CBlock().serialize().hex()))
 459  
 460          self.log.info('submitheader tests')
 461          assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * BLOCK_HEADER_SIZE))
 462          assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (BLOCK_HEADER_SIZE-2)))
 463  
 464          missing_ancestor_block = copy.deepcopy(block)
 465          missing_ancestor_block.hashPrevBlock = 123
 466          assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=super(CBlock, missing_ancestor_block).serialize().hex()))
 467  
 468          block.nTime += 1
 469          block.solve()
 470  
 471          def chain_tip(b_hash, *, status='headers-only', branchlen=1):
 472              return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}
 473  
 474          assert chain_tip(block.hash_hex) not in node.getchaintips()
 475          node.submitheader(hexdata=block.serialize().hex())
 476          assert chain_tip(block.hash_hex) in node.getchaintips()
 477          node.submitheader(hexdata=CBlockHeader(block).serialize().hex())  # Noop
 478          assert chain_tip(block.hash_hex) in node.getchaintips()
 479  
 480          bad_block_root = copy.deepcopy(block)
 481          bad_block_root.hashMerkleRoot += 2
 482          bad_block_root.solve()
 483          assert chain_tip(bad_block_root.hash_hex) not in node.getchaintips()
 484          node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
 485          assert chain_tip(bad_block_root.hash_hex) in node.getchaintips()
 486          # Should still reject invalid blocks, even if we have the header:
 487          assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
 488          assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
 489          assert chain_tip(bad_block_root.hash_hex) in node.getchaintips()
 490          # We know the header for this invalid block, so should just return early without error:
 491          node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
 492          assert chain_tip(bad_block_root.hash_hex) in node.getchaintips()
 493  
 494          bad_block_lock = copy.deepcopy(block)
 495          bad_block_lock.vtx[0].nLockTime = 2**32 - 1
 496          bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
 497          bad_block_lock.solve()
 498          assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'bad-txns-nonfinal')
 499          assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'duplicate-invalid')
 500          # Build a "good" block on top of the submitted bad block
 501          bad_block2 = copy.deepcopy(block)
 502          bad_block2.hashPrevBlock = bad_block_lock.hash_int
 503          bad_block2.solve()
 504          assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))
 505  
 506          # Should reject invalid header right away
 507          bad_block_time = copy.deepcopy(block)
 508          bad_block_time.nTime = 1
 509          bad_block_time.solve()
 510          assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))
 511  
 512          # Should ask for the block from a p2p node, if they announce the header as well:
 513          peer = node.add_p2p_connection(P2PDataStore())
 514          peer.wait_for_getheaders(timeout=5, block_hash=block.hashPrevBlock)
 515          peer.send_blocks_and_test(blocks=[block], node=node)
 516          # Must be active now:
 517          assert chain_tip(block.hash_hex, status='active', branchlen=0) in node.getchaintips()
 518  
 519          # Building a few blocks should give the same results
 520          self.generatetoaddress(node, 10, node.get_deterministic_priv_key().address)
 521          assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))
 522          assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))
 523          node.submitheader(hexdata=CBlockHeader(block).serialize().hex())
 524          node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
 525          assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate')  # valid
 526  
 527          self.test_fees_and_sigops()
 528          self.test_blockmintxfee_parameter()
 529          self.test_block_max_weight()
 530          self.test_timewarp()
 531          self.test_pruning()
 532          self.test_height_in_locktime()
 533  
 534  
 535  if __name__ == '__main__':
 536      MiningTest(__file__).main()
 537