feature_utxo_set_hash.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2020-2022 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(int(tx.rehash(), 16), 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'], "d1c7fec1c0623f6793839878cbe2a531eb968b50b27edd6e2a57077a5aed6094") 71 assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "d1725b2fe3ef43e55aa4907480aea98d406fc9e0bf8f60169e2305f1fbf5961b") 72 73 def run_test(self): 74 self.test_muhash_implementation() 75 76 77 if __name__ == '__main__': 78 UTXOSetHashTest().main()