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

Code before:
            self.log.debug("Wait for another, but time out")
            template3 = await template2.result.waitNext(ctx, waitoptions)
            assert_equal(template3.to_dict(), {})
            self.log.debug("Wait for another, get one after increase in fees in the mempool")
            waitnext = template2.result.waitNext(ctx, waitoptions)
            miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
            template4 = await waitnext
            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 template4.result.waitNext(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")
            waitnext = template5.result.waitNext(ctx, waitoptions)
            miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
            template6 = await waitnext
            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.result.waitNext(ctx, waitoptions)
            assert_equal(template7.to_dict(), {})

            current_block_height = self.nodes[0].getchaintips()[0]["height"]
            check_opts = self.capnp_modules['mining'].BlockCheckOptions()
            template = await mining.result.createNewBlock(opts)
            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()
            res = await mining.result.checkBlock(block.serialize(), check_opts)
            assert_equal(res.result, False)
            assert_equal(res.reason, "bad-version(0x00000000)")
            res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
            assert_equal(res.result, False)
            self.log.debug("Submit a valid block")
            block.nVersion = original_version
            block.solve()
            res = await mining.result.checkBlock(block.serialize(), check_opts)
            assert_equal(res.result, True)
            res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
            assert_equal(res.result, True)

Review comment (bug):
nit: you could move these helper methods out of the test:

```diff
diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py
index 0c9de28da0..7a447eba92 100755
--- a/test/functional/interface_ipc.py
+++ b/test/functional/interface_ipc.py
@@ -82,10 +82,20 @@ class IPCInterfaceTest(BitcoinTestFramework):
         coinbase_data = BytesIO((await block_template.result.getCoinbaseTx(ctx)).result)
         tx = CTransaction()
         tx.deserialize(coinbase_data)
         return tx

+    async def wait_for_block(self, template, waitoptions, ctx, wait_started):
+        wait_started.set()
+        return await template.result.waitNext(ctx, waitoptions)
+
+    async def interrupt_wait(self, template, miniwallet, wait_started):
+        await wait_started.wait() # Wait for confirmation wait started
+        await asyncio.sleep(0.1)  # Minimal buffer
+        template.result.interruptWait()
+        miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
+
     def run_echo_test(self):
         self.log.info("Running echo test")
         async def async_routine():
             ctx, init = await self.make_capnp_init_ctx()
             self.log.debug("Create Echo proxy object")
@@ -182,25 +192,15 @@ class IPCInterfaceTest(BitcoinTestFramework):
             template7 = await template6.result.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.result.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.result.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())
+            waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait
+            waitoptions.feeThreshold = 1
+            wait_task = asyncio.create_task(self.wait_for_block(template6, waitoptions, ctx, wait_started))
+            interrupt_task = asyncio.create_task(self.interrupt_wait(template6, miniwallet, wait_started))

             result = await wait_task
             await interrupt_task
             assert_equal(result.to_dict(), {})
```

Code after:
            template3 = await template2.result.waitNext(ctx, waitoptions)
            assert_equal(template3.to_dict(), {})
            self.log.debug("Wait for another, get one after increase in fees in the mempool")
            waitnext = template2.result.waitNext(ctx, waitoptions)
            miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
            template4 = await waitnext
            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")
            template5 = await template4.result.waitNext(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")
            waitnext = template5.result.waitNext(ctx, waitoptions)
            miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
            template6 = await waitnext
            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.result.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.result.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.result.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())

            result = await wait_task
            await interrupt_task
            assert_equal(result.to_dict(), {})

            current_block_height = self.nodes[0].getchaintips()[0]["height"]
            check_opts = self.capnp_modules['mining'].BlockCheckOptions()
            template = await mining.result.createNewBlock(opts)
            block = await self.parse_and_deserialize_block(template, ctx)
            coinbase = await self.parse_and_deserialize_coinbase_tx(template, ctx)
            balance = miniwallet.get_balance()