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 UTXO set hash value calculation in gettxoutsetinfo."""
6 7 from test_framework.messages import (
8 CBlock,
9 COutPoint,
10 from_hex,
11 )
12 from test_framework.crypto.muhash import MuHash3072
13 from test_framework.test_framework import BitcoinTestFramework
14 from test_framework.util import assert_equal
15 from test_framework.wallet import MiniWallet
16 17 class UTXOSetHashTest(BitcoinTestFramework):
18 def set_test_params(self):
19 self.num_nodes = 1
20 self.setup_clean_chain = True
21 22 def test_muhash_implementation(self):
23 self.log.info("Test MuHash implementation consistency")
24 25 node = self.nodes[0]
26 wallet = MiniWallet(node)
27 mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1
28 node.setmocktime(mocktime)
29 30 # Generate 100 blocks and remove the first since we plan to spend its
31 # coinbase
32 block_hashes = self.generate(wallet, 1) + self.generate(node, 99)
33 blocks = list(map(lambda block: from_hex(CBlock(), node.getblock(block, False)), block_hashes))
34 blocks.pop(0)
35 36 # Create a spending transaction and mine a block which includes it
37 txid = wallet.send_self_transfer(from_node=node)['txid']
38 tx_block = self.generateblock(node, output=wallet.get_address(), transactions=[txid])
39 blocks.append(from_hex(CBlock(), node.getblock(tx_block['hash'], False)))
40 41 # Serialize the outputs that should be in the UTXO set and add them to
42 # a MuHash object
43 muhash = MuHash3072()
44 45 for height, block in enumerate(blocks):
46 # The Genesis block coinbase is not part of the UTXO set and we
47 # spent the first mined block
48 height += 2
49 50 for tx in block.vtx:
51 for n, tx_out in enumerate(tx.vout):
52 coinbase = 1 if not tx.vin[0].prevout.hash else 0
53 54 # Skip witness commitment
55 if (coinbase and n > 0):
56 continue
57 58 data = COutPoint(tx.txid_int, n).serialize()
59 data += (height * 2 + coinbase).to_bytes(4, "little")
60 data += tx_out.serialize()
61 62 muhash.insert(data)
63 64 finalized = muhash.digest()
65 node_muhash = node.gettxoutsetinfo("muhash")['muhash']
66 67 assert_equal(finalized[::-1].hex(), node_muhash)
68 69 self.log.info("Test deterministic UTXO set hash results")
70 assert_equal(node.gettxoutsetinfo()['hash_serialized_3'], "396058cfd7f3b4c05dcdfaf360be9986d859d2c8315082d3aadda6d2d16add25")
71 assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "97f341d4226cb4451dd9da2856759fb97659cfc238a0b8d5452e64af6032bd3d")
72 73 def run_test(self):
74 self.test_muhash_implementation()
75 76 77 if __name__ == '__main__':
78 UTXOSetHashTest(__file__).main()
79