rpc_dumptxoutset.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2019-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 the generation of UTXO snapshots using `dumptxoutset`.
   6  """
   7  
   8  from test_framework.blocktools import COINBASE_MATURITY
   9  from test_framework.test_framework import BitcoinTestFramework
  10  from test_framework.util import (
  11      assert_equal,
  12      assert_raises_rpc_error,
  13      sha256sum_file,
  14  )
  15  
  16  
  17  class DumptxoutsetTest(BitcoinTestFramework):
  18      def set_test_params(self):
  19          self.setup_clean_chain = True
  20          self.num_nodes = 1
  21  
  22      def test_dumptxoutset_with_fork(self):
  23          node = self.nodes[0]
  24          tip = node.getbestblockhash()
  25          target_height = node.getblockcount() - 10
  26          target_hash = node.getblockhash(target_height)
  27  
  28          # Create a fork of two blocks at the target height
  29          invalid_block = node.getblockhash(target_height + 1)
  30          node.invalidateblock(invalid_block)
  31          # Reset mocktime to not regenerate the same blockhash
  32          node.setmocktime(0)
  33          self.generate(node, 2)
  34  
  35          # Move back on to actual main chain
  36          node.reconsiderblock(invalid_block)
  37          self.wait_until(lambda: node.getbestblockhash() == tip)
  38  
  39          # Use dumptxoutset at the forked height
  40          out = node.dumptxoutset("txoutset_fork.dat", "rollback", {"rollback": target_height})
  41  
  42          # Verify the snapshot was created at the target height and not the fork tip
  43          assert_equal(out['base_height'], target_height)
  44          assert_equal(out['base_hash'], target_hash)
  45  
  46          # Cover the same case as above with an in-memory database
  47          out_mem = node.dumptxoutset("txoutset_fork_mem.dat", "rollback", {"rollback": target_height, "in_memory": True})
  48          assert_equal(out_mem['base_height'], target_height)
  49          assert_equal(out_mem['base_hash'], target_hash)
  50  
  51  
  52      def run_test(self):
  53          """Test a trivial usage of the dumptxoutset RPC command."""
  54          node = self.nodes[0]
  55          mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1
  56          node.setmocktime(mocktime)
  57          self.generate(node, COINBASE_MATURITY)
  58  
  59          FILENAME = 'txoutset.dat'
  60          out = node.dumptxoutset(FILENAME, "latest")
  61          expected_path = node.chain_path / FILENAME
  62  
  63          assert expected_path.is_file()
  64  
  65          assert_equal(out['coins_written'], 100)
  66          assert_equal(out['base_height'], 100)
  67          assert_equal(out['path'], str(expected_path))
  68          # Blockhash should be deterministic based on mocked time.
  69          assert_equal(
  70              out['base_hash'],
  71              '220aee93f0f5409631f35488898258f0930952bd620063cb4d7d87f7c28a8f50')
  72  
  73          # UTXO snapshot hash should be deterministic based on mocked time.
  74          assert_equal(
  75              sha256sum_file(str(expected_path)).hex(),
  76              'e8c59b1bc1f19061c67eb7a392f4ea17eea83af58646ea2909e270546699c36c')
  77  
  78          assert_equal(
  79              out['txoutset_hash'], '771d773b5c27b6f35f598ce764652a2cf28fbc268341eb1827844e416c629c7d')
  80          assert_equal(out['nchaintx'], 101)
  81  
  82          # Specifying a path to an existing or invalid file will fail.
  83          assert_raises_rpc_error(
  84              -8, '{} already exists'.format(FILENAME),  node.dumptxoutset, FILENAME, "latest")
  85          invalid_path = node.datadir_path / "invalid" / "path"
  86          assert_raises_rpc_error(
  87              -8, "Couldn't open file {}.incomplete for writing".format(invalid_path), node.dumptxoutset, invalid_path, "latest")
  88  
  89          self.log.info("Test that dumptxoutset with unknown dump type fails")
  90          assert_raises_rpc_error(
  91              -8, 'Invalid snapshot type "bogus" specified. Please specify "rollback" or "latest"', node.dumptxoutset, 'utxos.dat', "bogus")
  92  
  93          self.log.info("Testing dumptxoutset with chain fork at target height")
  94          self.test_dumptxoutset_with_fork()
  95  
  96  
  97  if __name__ == '__main__':
  98      DumptxoutsetTest(__file__).main()
  99