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

Code before:

                self.log.debug("Wait for another, get one after increase in fees in the mempool")
                template4 = await wait_and_do(
                    wait_next_template(template2, stack, ctx, waitoptions),
                    lambda: miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0]))
                block3 = await self.parse_and_deserialize_block(template4, ctx)
                assert_equal(len(block3.vtx), 2)

                self.log.debug("Wait again, this should return the same template, since the fee threshold is zero")
                waitoptions.feeThreshold = 0
                template5 = await wait_next_template(template4, stack, ctx, waitoptions)
                block4 = await self.parse_and_deserialize_block(template5, ctx)
                assert_equal(len(block4.vtx), 2)
                waitoptions.feeThreshold = 1

                self.log.debug("Wait for another, get one after increase in fees in the mempool")
                template6 = await wait_and_do(
                    wait_next_template(template5, stack, ctx, waitoptions),
                    lambda: miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0]))
                block4 = await self.parse_and_deserialize_block(template6, ctx)
                assert_equal(len(block4.vtx), 3)

                self.log.debug("Wait for another, but time out, since the fee threshold is set now")
                template7 = await template6.waitNext(ctx, waitoptions)
                assert_equal(template7._has("result"), False)

                self.log.debug("interruptWait should abort the current wait")
                async def wait_for_block():
                    new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
                    new_waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait
                    new_waitoptions.feeThreshold = 1
                    template7 = await template6.waitNext(ctx, new_waitoptions)
                    assert_equal(template7._has("result"), False)
                await wait_and_do(wait_for_block(), template6.interruptWait())

            current_block_height = self.nodes[0].getchaintips()[0]["height"]
            check_opts = self.capnp_modules['mining'].BlockCheckOptions()
            async with destroying((await mining.createNewBlock(opts)).result, ctx) as template:
                block = await self.parse_and_deserialize_block(template, ctx)
                coinbase = await self.parse_and_deserialize_coinbase_tx(template, ctx)
                balance = miniwallet.get_balance()
                coinbase.vout[0].scriptPubKey = miniwallet.get_output_script()
                coinbase.vout[0].nValue = COIN
                block.vtx[0] = coinbase
                block.hashMerkleRoot = block.calc_merkle_root()
                original_version = block.nVersion
                self.log.debug("Submit a block with a bad version")
                block.nVersion = 0
                block.solve()
                check = await mining.checkBlock(block.serialize(), check_opts)
                assert_equal(check.result, False)

Review comment (suggestion):
In case of `has_witness`, `coinbase_commitment` and `coinbase_template.witness` could be directly compared here.

Code after:
        # empty blocks, but this may change.
        found_witness_op_return = False
        # Compare SegWit OP_RETURN to getCoinbaseCommitment()
        coinbase_commitment = (await template.getCoinbaseCommitment(ctx)).result
        for output_data in coinbase_res.requiredOutputs:
            output = CTxOut()
            output.deserialize(BytesIO(output_data))
            coinbase_tx.vout.append(output)
            if output.scriptPubKey == coinbase_commitment:
                found_witness_op_return = True

        assert_equal(has_witness, found_witness_op_return)

        coinbase_tx.nLockTime = coinbase_res.lockTime

        # Compare to dummy coinbase provided by the deprecated getCoinbaseTx()
        coinbase_legacy = await self.parse_and_deserialize_coinbase_tx(template, ctx)
        assert_equal(coinbase_legacy.vout[0].nValue, coinbase_res.blockRewardRemaining)
        # Swap dummy output for our own
        coinbase_legacy.vout[0].scriptPubKey = coinbase_tx.vout[0].scriptPubKey
        assert_equal(coinbase_tx.serialize().hex(), coinbase_legacy.serialize().hex())

        return coinbase_tx

    def run_mining_test(self):
        self.log.info("Running mining test")
        block_hash_size = 32
        block_header_size = 80
        timeout = 1000.0 # 1000 milliseconds
        miniwallet = MiniWallet(self.nodes[0])

        async def async_routine():
            ctx, init = await self.make_capnp_init_ctx()
            self.log.debug("Create Mining proxy object")
            mining = init.makeMining(ctx).result
            self.log.debug("Test simple inspectors")
            assert (await mining.isTestChain(ctx)).result
            assert not (await mining.isInitialBlockDownload(ctx)).result
            blockref = await mining.getTip(ctx)
            assert blockref.hasResult
            assert_equal(len(blockref.result.hash), block_hash_size)
            current_block_height = self.nodes[0].getchaintips()[0]["height"]
            assert blockref.result.height == current_block_height
            self.log.debug("Mine a block")
            newblockref = (await wait_and_do(
                mining.waitTipChanged(ctx, blockref.result.hash, timeout),
                lambda: self.generate(self.nodes[0], 1))).result
            assert_equal(len(newblockref.hash), block_hash_size)
            assert_equal(newblockref.height, current_block_height + 1)
            self.log.debug("Wait for timeout")
            oldblockref = (await mining.waitTipChanged(ctx, newblockref.hash, timeout)).result