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