Repository: bitcoin/bitcoin
File: test/functional/feature_taproot.py (Python)

Code before:
            fund_tx.vout.append(CTxOut(balance - 10000, random.choice(host_spks)))
            # Ask the wallet to sign
            fund_tx = tx_from_hex(node.signrawtransactionwithwallet(fund_tx.serialize().hex())["hex"])
            # Construct UTXOData entries
            fund_tx.rehash()
            for i in range(count_this_tx):
                utxodata = UTXOData(outpoint=COutPoint(fund_tx.sha256, i), output=fund_tx.vout[i], spender=spenders[done])
                if utxodata.spender.need_vin_vout_mismatch:
                    mismatching_utxos.append(utxodata)
                else:
                    normal_utxos.append(utxodata)
                done += 1
            # Mine into a block
            self.block_submit(node, [fund_tx], "Funding tx", None, random.choice(host_pubkeys), 10000, MAX_BLOCK_SIGOPS_WEIGHT, True, True)

        # Consume groups of choice(input_coins) from utxos in a tx, testing the spenders.
        self.log.info("- Running %i spending tests" % done)
        random.shuffle(normal_utxos)
        random.shuffle(mismatching_utxos)
        assert done == len(normal_utxos) + len(mismatching_utxos)

        left = done
        while left:
            # Construct CTransaction with random nVersion, nLocktime
            tx = CTransaction()
            tx.nVersion = random.choice([1, 2, random.randint(-0x80000000, 0x7fffffff)])
            min_sequence = (tx.nVersion != 1 and tx.nVersion != 0) * 0x80000000  # The minimum sequence number to disable relative locktime
            if random.choice([True, False]):
                tx.nLockTime = random.randrange(LOCKTIME_THRESHOLD, self.lastblocktime - 7200)  # all absolute locktimes in the past
            else:
                tx.nLockTime = random.randrange(self.lastblockheight + 1)  # all block heights in the past

            # Decide how many UTXOs to test with.
            acceptable = [n for n in input_counts if n <= left and (left - n > max(input_counts) or (left - n) in [0] + input_counts)]
            num_inputs = random.choice(acceptable)

            # If we have UTXOs that require mismatching inputs/outputs left, include exactly one of those
            # unless there is only one normal UTXO left (as tests with mismatching UTXOs require at least one
            # normal UTXO to go in the first position), and we don't want to run out of normal UTXOs.
            input_utxos = []
            while len(mismatching_utxos) and (len(input_utxos) == 0 or len(normal_utxos) == 1):
                input_utxos.append(mismatching_utxos.pop())
                left -= 1

            # Top up until we hit num_inputs (but include at least one normal UTXO always).
            for _ in range(max(1, num_inputs - len(input_utxos))):
                input_utxos.append(normal_utxos.pop())
                left -= 1

            # The first input cannot require a mismatching output (as there is at least one output).
            while True:

Review comment (suggestion):
```suggestion
            tx.nVersion = random.choice([1, 2, random.randbits(32)])
```

nit: No need to call the randbits wrapper

Code after:
            fund_tx.vout.append(CTxOut(balance - 10000, random.choice(host_spks)))
            # Ask the wallet to sign
            fund_tx = tx_from_hex(node.signrawtransactionwithwallet(fund_tx.serialize().hex())["hex"])
            # Construct UTXOData entries
            fund_tx.rehash()
            for i in range(count_this_tx):
                utxodata = UTXOData(outpoint=COutPoint(fund_tx.sha256, i), output=fund_tx.vout[i], spender=spenders[done])
                if utxodata.spender.need_vin_vout_mismatch:
                    mismatching_utxos.append(utxodata)
                else:
                    normal_utxos.append(utxodata)
                done += 1
            # Mine into a block
            self.block_submit(node, [fund_tx], "Funding tx", None, random.choice(host_pubkeys), 10000, MAX_BLOCK_SIGOPS_WEIGHT, True, True)

        # Consume groups of choice(input_coins) from utxos in a tx, testing the spenders.
        self.log.info("- Running %i spending tests" % done)
        random.shuffle(normal_utxos)
        random.shuffle(mismatching_utxos)
        assert done == len(normal_utxos) + len(mismatching_utxos)

        left = done
        while left:
            # Construct CTransaction with random version, nLocktime
            tx = CTransaction()
            tx.version = random.choice([1, 2, random.getrandbits(32)])
            min_sequence = (tx.version != 1 and tx.version != 0) * 0x80000000  # The minimum sequence number to disable relative locktime
            if random.choice([True, False]):
                tx.nLockTime = random.randrange(LOCKTIME_THRESHOLD, self.lastblocktime - 7200)  # all absolute locktimes in the past
            else:
                tx.nLockTime = random.randrange(self.lastblockheight + 1)  # all block heights in the past

            # Decide how many UTXOs to test with.
            acceptable = [n for n in input_counts if n <= left and (left - n > max(input_counts) or (left - n) in [0] + input_counts)]
            num_inputs = random.choice(acceptable)

            # If we have UTXOs that require mismatching inputs/outputs left, include exactly one of those
            # unless there is only one normal UTXO left (as tests with mismatching UTXOs require at least one
            # normal UTXO to go in the first position), and we don't want to run out of normal UTXOs.
            input_utxos = []
            while len(mismatching_utxos) and (len(input_utxos) == 0 or len(normal_utxos) == 1):
                input_utxos.append(mismatching_utxos.pop())
                left -= 1

            # Top up until we hit num_inputs (but include at least one normal UTXO always).
            for _ in range(max(1, num_inputs - len(input_utxos))):
                input_utxos.append(normal_utxos.pop())
                left -= 1

            # The first input cannot require a mismatching output (as there is at least one output).
            while True: