/ test / functional / feature_utxo_set_hash.py
feature_utxo_set_hash.py
 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'], "e0b4c80f2880985fdf1adc331ed0735ac207588f986c91c7c05e8cf5fe6780f0")
71          assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "8739b878f23030ef39a5547edc7b57f88d50fdaaf47314ff0524608deb13067e")
72  
73      def run_test(self):
74          self.test_muhash_implementation()
75  
76  
77  if __name__ == '__main__':
78      UTXOSetHashTest(__file__).main()