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

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

                await asyncio.gather(wait_for_block(), interrupt_wait())

            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)
                assert_equal(check.reason, "bad-version(0x00000000)")
                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
                assert_equal(submit.result, False)
                self.log.debug("Submit a valid block")
                block.nVersion = original_version
                block.solve()

                self.log.debug("First call checkBlock()")
                check = await mining.checkBlock(block.serialize(), check_opts)
                assert_equal(check.result, True)

                # The remote template block will be mutated, capture the original:
                remote_block_before = await self.parse_and_deserialize_block(template, ctx)

                self.log.debug("Submitted coinbase must include witness")
                assert_not_equal(coinbase.serialize_without_witness().hex(), coinbase.serialize().hex())
                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize_without_witness())
                assert_equal(submit.result, False)

                self.log.debug("Even a rejected submitBlock() mutates the template's block")
                # Can be used by clients to download and inspect the (rejected)
                # reconstructed block.
                remote_block_after = await self.parse_and_deserialize_block(template, ctx)
                assert_not_equal(remote_block_before.serialize().hex(), remote_block_after.serialize().hex())

                self.log.debug("Submit again, with the witness")
                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())

Review comment (bug):
In 6ef092c0e4343fc421c323ff09d3c791fb4bc33a "test: interface_ipc.py minor fixes and cleanup"

> A lot of result accesses like `template.result` `mining.result` were repeated
  unnecessarily because variables like `template` and `mining` were assigned
  response objects instead of result objects. These variables are now changed
  to point directly to results.

Along the same lines:

```diff
diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py
index 90e22285e6..756c115c7e 100755
--- a/test/functional/interface_ipc.py
+++ b/test/functional/interface_ipc.py
@@ -234,23 +234,23 @@ class IPCInterfaceTest(BitcoinTestFramework):
                 check = await mining.checkBlock(block.serialize(), check_opts)
                 assert_equal(check.result, False)
                 assert_equal(check.reason, "bad-version(0x00000000)")
-                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
-                assert_equal(submit.result, False)
+                submitted = (await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())).result
+                assert_equal(submitted, False)
                 self.log.debug("Submit a valid block")
                 block.nVersion = original_version
                 block.solve()
 
                 self.log.debug("First call checkBlock()")
-                check = await mining.checkBlock(block.serialize(), check_opts)
-                assert_equal(check.result, True)
+                block_valid = (await mining.checkBlock(block.serialize(), check_opts)).result
+                assert_equal(block_valid, True)
 
                 # The remote template block will be mutated, capture the original:
                 remote_block_before = await self.parse_and_deserialize_block(template, ctx)
 
                 self.log.debug("Submitted coinbase must include witness")
                 assert_not_equal(coinbase.serialize_without_witness().hex(), coinbase.serialize().hex())
-                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize_without_witness())
-                assert_equal(submit.result, False)
+                submitted = (await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize_without_witness())).result
+                assert_equal(submitted, False)
 
                 self.log.debug("Even a rejected submitBlock() mutates the template's block")
                 # Can be used by clients to download and inspect the (rejected)
@@ -259,8 +259,8 @@ class IPCInterfaceTest(BitcoinTestFramework):
                 assert_not_equal(remote_block_before.serialize().hex(), remote_block_after.serialize().hex())
 
                 self.log.debug("Submit again, with the witness")
-                submit = await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
-                assert_equal(submit.result, True)
+                submitted = (await template.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())).result
+                assert_equal(submitted, True)
 
             self.log.debug("Block should propagate")
             # Check that the IPC node actually updates its own chain
```

Code after:

                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)