rpc_generate.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2020-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 generate* RPCs."""
   6  
   7  from concurrent.futures import ThreadPoolExecutor
   8  
   9  from test_framework.test_framework import BitcoinTestFramework
  10  from test_framework.wallet import MiniWallet
  11  from test_framework.util import (
  12      assert_equal,
  13      assert_raises_rpc_error,
  14  )
  15  
  16  
  17  class RPCGenerateTest(BitcoinTestFramework):
  18      def set_test_params(self):
  19          self.num_nodes = 1
  20  
  21      def run_test(self):
  22          self.test_generatetoaddress()
  23          self.test_generate()
  24          self.test_generateblock()
  25  
  26      def test_generatetoaddress(self):
  27          self.generatetoaddress(self.nodes[0], 1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
  28          assert_raises_rpc_error(-5, "Invalid address", self.generatetoaddress, self.nodes[0], 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
  29  
  30      def test_generateblock(self):
  31          node = self.nodes[0]
  32          miniwallet = MiniWallet(node)
  33  
  34          self.log.info('Mine an empty block to address and return the hex')
  35          address = miniwallet.get_address()
  36          generated_block = self.generateblock(node, output=address, transactions=[], submit=False)
  37          node.submitblock(hexdata=generated_block['hex'])
  38          assert_equal(generated_block['hash'], node.getbestblockhash())
  39  
  40          self.log.info('Generate an empty block to address')
  41          hash = self.generateblock(node, output=address, transactions=[])['hash']
  42          block = node.getblock(blockhash=hash, verbose=2)
  43          assert_equal(len(block['tx']), 1)
  44          assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], address)
  45  
  46          self.log.info('Generate an empty block to a descriptor')
  47          hash = self.generateblock(node, 'addr(' + address + ')', [])['hash']
  48          block = node.getblock(blockhash=hash, verbosity=2)
  49          assert_equal(len(block['tx']), 1)
  50          assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], address)
  51  
  52          self.log.info('Generate an empty block to a combo descriptor with compressed pubkey')
  53          combo_key = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'
  54          combo_address = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080'
  55          hash = self.generateblock(node, 'combo(' + combo_key + ')', [])['hash']
  56          block = node.getblock(hash, 2)
  57          assert_equal(len(block['tx']), 1)
  58          assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
  59  
  60          self.log.info('Generate an empty block to a combo descriptor with uncompressed pubkey')
  61          combo_key = '0408ef68c46d20596cc3f6ddf7c8794f71913add807f1dc55949fa805d764d191c0b7ce6894c126fce0babc6663042f3dde9b0cf76467ea315514e5a6731149c67'
  62          combo_address = 'mkc9STceoCcjoXEXe6cm66iJbmjM6zR9B2'
  63          hash = self.generateblock(node, 'combo(' + combo_key + ')', [])['hash']
  64          block = node.getblock(hash, 2)
  65          assert_equal(len(block['tx']), 1)
  66          assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
  67  
  68          # Generate some extra mempool transactions to verify they don't get mined
  69          for _ in range(10):
  70              miniwallet.send_self_transfer(from_node=node)
  71  
  72          self.log.info('Generate block with txid')
  73          txid = miniwallet.send_self_transfer(from_node=node)['txid']
  74          hash = self.generateblock(node, address, [txid])['hash']
  75          block = node.getblock(hash, 1)
  76          assert_equal(len(block['tx']), 2)
  77          assert_equal(block['tx'][1], txid)
  78  
  79          self.log.info('Generate block with raw tx')
  80          rawtx = miniwallet.create_self_transfer()['hex']
  81          hash = self.generateblock(node, address, [rawtx])['hash']
  82  
  83          block = node.getblock(hash, 1)
  84          assert_equal(len(block['tx']), 2)
  85          txid = block['tx'][1]
  86          assert_equal(node.getrawtransaction(txid=txid, verbose=False, blockhash=hash), rawtx)
  87  
  88          # Ensure that generateblock can be called concurrently by many threads.
  89          self.log.info('Generate blocks in parallel')
  90          generate_50_blocks = lambda n: [n.generateblock(output=address, transactions=[]) for _ in range(50)]
  91          rpcs = [node.cli for _ in range(6)]
  92          with ThreadPoolExecutor(max_workers=len(rpcs)) as threads:
  93              list(threads.map(generate_50_blocks, rpcs))
  94  
  95          self.log.info('Fail to generate block with out of order txs')
  96          txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
  97          utxo1 = miniwallet.get_utxo(txid=txid1)
  98          rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
  99          assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
 100  
 101          self.log.info('Fail to generate block with txid not in mempool')
 102          missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
 103          assert_raises_rpc_error(-5, 'Transaction ' + missing_txid + ' not in mempool.', self.generateblock, node, address, [missing_txid])
 104  
 105          self.log.info('Fail to generate block with invalid raw tx')
 106          invalid_raw_tx = '0000'
 107          assert_raises_rpc_error(-22, 'Transaction decode failed for ' + invalid_raw_tx, self.generateblock, node, address, [invalid_raw_tx])
 108  
 109          self.log.info('Fail to generate block with invalid address/descriptor')
 110          assert_raises_rpc_error(-5, 'Invalid address or descriptor', self.generateblock, node, '1234', [])
 111  
 112          self.log.info('Fail to generate block with a ranged descriptor')
 113          ranged_descriptor = 'pkh(tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp/0/*)'
 114          assert_raises_rpc_error(-8, 'Ranged descriptor not accepted. Maybe pass through deriveaddresses first?', self.generateblock, node, ranged_descriptor, [])
 115  
 116          self.log.info('Fail to generate block with a descriptor missing a private key')
 117          child_descriptor = 'pkh(tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp/0\'/0)'
 118          assert_raises_rpc_error(-5, 'Cannot derive script without private keys', self.generateblock, node, child_descriptor, [])
 119  
 120      def test_generate(self):
 121          message = (
 122              "generate\n\n"
 123              "has been replaced by the -generate "
 124              "cli option. Refer to -help for more information.\n"
 125          )
 126  
 127          if not self.options.usecli:
 128              self.log.info("Test rpc generate raises with message to use cli option")
 129              assert_raises_rpc_error(-32601, message, self.nodes[0]._rpc.generate)
 130  
 131              self.log.info("Test rpc generate help prints message to use cli option")
 132              assert_equal(message, self.nodes[0].help("generate"))
 133  
 134          self.log.info("Test rpc generate is a hidden command not discoverable in general help")
 135          assert message not in self.nodes[0].help()
 136  
 137  
 138  if __name__ == "__main__":
 139      RPCGenerateTest(__file__).main()
 140