feature_blocksxor.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2024 The Limenka 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 support for XORed block data and undo files (`-blocksxor` option)."""
   6  
   7  from test_framework.test_framework import LimenkaTestFramework
   8  from test_framework.test_node import (
   9      ErrorMatch,
  10      NULL_BLK_XOR_KEY,
  11  )
  12  from test_framework.util import (
  13      assert_equal,
  14      assert_greater_than,
  15      util_xor,
  16  )
  17  from test_framework.wallet import MiniWallet
  18  
  19  
  20  class BlocksXORTest(LimenkaTestFramework):
  21      def set_test_params(self):
  22          self.num_nodes = 1
  23          self.extra_args = [[
  24              '-blocksxor=1',
  25              '-fastprune=1',             # use smaller block files
  26              '-datacarriersize=100000',  # needed to pad transaction with MiniWallet
  27          ]]
  28  
  29      def run_test(self):
  30          self.log.info("Mine some blocks, to create multiple blk*.dat/rev*.dat files")
  31          node = self.nodes[0]
  32          wallet = MiniWallet(node)
  33          for _ in range(5):
  34              wallet.send_self_transfer(from_node=node, target_vsize=20000)
  35              self.generate(wallet, 1)
  36  
  37          block_files = list(node.blocks_path.glob('blk[0-9][0-9][0-9][0-9][0-9].dat'))
  38          undo_files  = list(node.blocks_path.glob('rev[0-9][0-9][0-9][0-9][0-9].dat'))
  39          assert_equal(len(block_files), len(undo_files))
  40          assert_greater_than(len(block_files), 1)  # we want at least one full block file
  41  
  42          self.log.info("Shut down node and un-XOR block/undo files manually")
  43          self.stop_node(0)
  44          xor_key = node.read_xor_key()
  45          for data_file in sorted(block_files + undo_files):
  46              self.log.debug(f"Rewriting file {data_file}...")
  47              with open(data_file, 'rb+') as f:
  48                  xored_data = f.read()
  49                  f.seek(0)
  50                  f.write(util_xor(xored_data, xor_key, offset=0))
  51  
  52          self.log.info("Check that restarting with 'blocksxor=0' fails if XOR key is present")
  53          node.assert_start_raises_init_error(['-blocksxor=0'],
  54              'The blocksdir XOR-key can not be disabled when a random key was already stored!',
  55              match=ErrorMatch.PARTIAL_REGEX)
  56  
  57          self.log.info("Delete XOR key, restart node with '-blocksxor=0', check blk*.dat/rev*.dat file integrity")
  58          node.blocks_key_path.unlink()
  59          self.start_node(0, extra_args=['-blocksxor=0'])
  60          # checklevel=2 -> verify block validity + undo data
  61          # nblocks=0    -> verify all blocks
  62          node.verifychain(checklevel=2, nblocks=0)
  63          self.log.info("Check that blocks XOR key is recreated")
  64          assert_equal(node.read_xor_key(), NULL_BLK_XOR_KEY)
  65  
  66  
  67  if __name__ == '__main__':
  68      BlocksXORTest(__file__).main()
  69