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

Code before:
                coinbase.deserialize(coinbase_data)
                assert_equal(coinbase.vin[0].prevout.hash, 0)
                self.log.debug("Wait for a new template")
                waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
                waitoptions.timeout = timeout
                waitoptions.feeThreshold = 1
                self.generate(self.nodes[0], 1)
                template2 = await stack.enter_async_context(destroying((await template.waitNext(ctx, waitoptions)).result, ctx))
                block2 = await self.parse_and_deserialize_block(template2, ctx)
                assert_equal(len(block2.vtx), 1)
                self.log.debug("Wait for another, but time out")
                template3 = await template2.waitNext(ctx, waitoptions)
                assert_equal(template3.to_dict(), {})
                self.log.debug("Wait for another, get one after increase in fees in the mempool")
                miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
                template4 = await stack.enter_async_context(destroying((await template2.waitNext(ctx, waitoptions)).result, ctx))
                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 stack.enter_async_context(destroying((await template4.waitNext(ctx, waitoptions)).result, ctx))
                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")
                miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
                template6 = await stack.enter_async_context(destroying((await template5.waitNext(ctx, waitoptions)).result, ctx))
                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.to_dict(), {})

                self.log.debug("interruptWait should abort the current wait")
                wait_started = asyncio.Event()
                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
                    wait_started.set()
                    return await template6.waitNext(ctx, new_waitoptions)

                async def interrupt_wait():
                    await wait_started.wait() # Wait for confirmation wait started
                    await asyncio.sleep(0.1)  # Minimal buffer
                    template6.interruptWait()
                    miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])

                wait_task = asyncio.create_task(wait_for_block())
                interrupt_task = asyncio.create_task(interrupt_wait())


Review comment (suggestion):
In https://github.com/bitcoin/bitcoin/commit/fac12f7cf9ebc0b906bbb20ae126cf7e7552fdbb _test: fix interface_ipc.py template destruction_: similar to my comment above, this only shows that `waitNext()` returns immediately if fees have gone up before the call, but the original intent was to show that a fee increase causes the wait to be interrupted.



Code after:
            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
            assert_equal(len(newblockref.hash), block_hash_size)
            assert_equal(oldblockref.hash, newblockref.hash)
            assert_equal(oldblockref.height, newblockref.height)

            async with AsyncExitStack() as stack:
                self.log.debug("Create a template")
                opts = self.capnp_modules['mining'].BlockCreateOptions()
                opts.useMempool = True
                opts.blockReservedWeight = 4000
                opts.coinbaseOutputMaxAdditionalSigops = 0
                template = await create_block_template(mining, stack, ctx, opts)

                self.log.debug("Test some inspectors of Template")
                header = (await template.getBlockHeader(ctx)).result
                assert_equal(len(header), block_header_size)
                block = await self.parse_and_deserialize_block(template, ctx)
                assert_equal(ser_uint256(block.hashPrevBlock), newblockref.hash)
                assert len(block.vtx) >= 1
                txfees = await template.getTxFees(ctx)
                assert_equal(len(txfees.result), 0)
                txsigops = await template.getTxSigops(ctx)
                assert_equal(len(txsigops.result), 0)
                coinbase_data = BytesIO((await template.getCoinbaseTx(ctx)).result)
                coinbase = CTransaction()
                coinbase.deserialize(coinbase_data)
                assert_equal(coinbase.vin[0].prevout.hash, 0)

                self.log.debug("Wait for a new template")
                waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
                waitoptions.timeout = timeout
                waitoptions.feeThreshold = 1
                template2 = await wait_and_do(
                    wait_next_template(template, stack, ctx, waitoptions),
                    lambda: self.generate(self.nodes[0], 1))
                block2 = await self.parse_and_deserialize_block(template2, ctx)
                assert_equal(len(block2.vtx), 1)

                self.log.debug("Wait for another, but time out")
                template3 = await template2.waitNext(ctx, waitoptions)
                assert_equal(template3._has("result"), False)

                self.log.debug("Wait for another, get one after increase in fees in the mempool")
                template4 = await wait_and_do(