feature_utxo_set_hash.py raw

   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