Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2024-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test utxo-to-sqlite conversion tool"""6from itertools import product7import os8import platform9try:10import sqlite311except ImportError:12pass13import subprocess14import sys16from test_framework.key import ECKey17from test_framework.messages import (18COutPoint,19CTxOut,20uint256_from_str,21)22from test_framework.crypto.muhash import MuHash307223from test_framework.script import (24CScript,25CScriptOp,26)27from test_framework.script_util import (28PAY_TO_ANCHOR,29key_to_p2pk_script,30key_to_p2pkh_script,31key_to_p2wpkh_script,32keys_to_multisig_script,33output_key_to_p2tr_script,34script_to_p2sh_script,35script_to_p2wsh_script,36)37from test_framework.test_framework import BitcoinTestFramework38from test_framework.util import (39assert_equal,40)41from test_framework.wallet import MiniWallet44def calculate_muhash_from_sqlite_utxos(filename, txid_format, spk_format):45muhash = MuHash3072()46con = sqlite3.connect(filename)47cur = con.cursor()48for (txid, vout, value, coinbase, height, spk) in cur.execute("SELECT * FROM utxos"):49match txid_format:50case "hex":51assert type(txid) is str52txid_bytes = bytes.fromhex(txid)[::-1]53case "raw":54assert type(txid) is bytes55txid_bytes = txid56case "rawle":57assert type(txid) is bytes58txid_bytes = txid[::-1]59match spk_format:60case "hex":61assert type(spk) is str62spk_bytes = bytes.fromhex(spk)63case "raw":64assert type(spk) is bytes65spk_bytes = spk67# serialize UTXO for MuHash (see function `TxOutSer` in the coinstats module)68utxo_ser = COutPoint(uint256_from_str(txid_bytes), vout).serialize()69utxo_ser += (height * 2 + coinbase).to_bytes(4, 'little')70utxo_ser += CTxOut(value, spk_bytes).serialize()71muhash.insert(utxo_ser)72con.close()73return muhash.digest()[::-1].hex()76class UtxoToSqliteTest(BitcoinTestFramework):77def set_test_params(self):78self.num_nodes = 179# we want to create some UTXOs with non-standard output scripts80self.extra_args = [['-acceptnonstdtxn=1', '-coinstatsindex=1']]82def skip_test_if_missing_module(self):83self.skip_if_no_py_sqlite3()85def run_test(self):86node = self.nodes[0]87wallet = MiniWallet(node)88key = ECKey()90self.log.info('Create UTXOs with various output script types')91for i in range(1, 10+1):92key.generate(compressed=False)93uncompressed_pubkey = key.get_pubkey().get_bytes()94key.generate(compressed=True)95pubkey = key.get_pubkey().get_bytes()97# add output scripts for compressed script type 0 (P2PKH), type 1 (P2SH),98# types 2-3 (P2PK compressed), types 4-5 (P2PK uncompressed) and99# for uncompressed scripts (bare multisig, segwit, etc.)100output_scripts = (101key_to_p2pkh_script(pubkey),102script_to_p2sh_script(key_to_p2pkh_script(pubkey)),103key_to_p2pk_script(pubkey),104key_to_p2pk_script(uncompressed_pubkey),106keys_to_multisig_script([pubkey]*i),107keys_to_multisig_script([uncompressed_pubkey]*i),108key_to_p2wpkh_script(pubkey),109script_to_p2wsh_script(key_to_p2pkh_script(pubkey)),110output_key_to_p2tr_script(pubkey[1:]),111PAY_TO_ANCHOR,112CScript([CScriptOp.encode_op_n(i)]*(1000*i)), # large script (up to 10000 bytes)113)115# create outputs and mine them in a block116for output_script in output_scripts:117wallet.send_to(from_node=node, scriptPubKey=output_script, amount=i, fee=20000)118self.generate(wallet, 1)120self.log.info('Dump UTXO set via `dumptxoutset` RPC')121input_filename = os.path.join(self.options.tmpdir, "utxos.dat")122node.dumptxoutset(input_filename, "latest")124for i, (txid_format, spk_format) in enumerate(product(["hex", "raw", "rawle"], ["hex", "raw"])):125self.log.info(f'Test utxo-to-sqlite script using txid format "{txid_format}" and spk format "{spk_format}" ({i+1})')126self.log.info('-> Convert UTXO set from compact-serialized format to sqlite format')127output_filename = os.path.join(self.options.tmpdir, f"utxos_{i+1}.sqlite")128base_dir = self.config["environment"]["SRCDIR"]129utxo_to_sqlite_path = os.path.join(base_dir, "contrib", "utxo-tools", "utxo_to_sqlite.py")130arguments = [input_filename, output_filename, f'--txid={txid_format}', f'--spk={spk_format}']131subprocess.run([sys.executable, utxo_to_sqlite_path] + arguments, check=True, stderr=subprocess.STDOUT)133self.log.info('-> Verify that both UTXO sets match by comparing their MuHash')134muhash_sqlite = calculate_muhash_from_sqlite_utxos(output_filename, txid_format, spk_format)135muhash_compact_serialized = node.gettxoutsetinfo('muhash')['muhash']136assert_equal(muhash_sqlite, muhash_compact_serialized)137self.log.info('')139if platform.system() != "Windows": # FIFOs are not available on Windows140self.log.info('Convert UTXO set directly (without intermediate dump) via named pipe')141fifo_filename = os.path.join(self.options.tmpdir, "utxos.fifo")142os.mkfifo(fifo_filename)143output_direct_filename = os.path.join(self.options.tmpdir, "utxos_direct.sqlite")144p = subprocess.Popen([sys.executable, utxo_to_sqlite_path, fifo_filename, output_direct_filename],145stderr=subprocess.STDOUT)146target_height = node.getblockcount() - 10147node.dumptxoutset(fifo_filename, "rollback", {"rollback": target_height})148p.wait(timeout=10)149muhash_direct_sqlite = calculate_muhash_from_sqlite_utxos(output_direct_filename, "hex", "hex")150muhash_index = node.gettxoutsetinfo('muhash', target_height)['muhash']151assert_equal(muhash_index, muhash_direct_sqlite)152os.remove(fifo_filename)155if __name__ == "__main__":156UtxoToSqliteTest(__file__).main()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.