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

Code before:
            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)
            assert_equal(self.nodes[0].getchaintips()[0]["height"], current_block_height + 1)
            miniwallet.rescan_utxos()
            assert_equal(miniwallet.get_balance(), balance + 1)
            self.log.debug("Check block should fail now, since it is a duplicate")
            res = await mining.result.checkBlock(block.serialize(), check_opts)
            assert_equal(res.result, False)
            assert_equal(res.reason, "inconclusive-not-best-prevblk")

            self.log.debug("Destroy template objects")
            template.result.destroy(ctx)
            template2.result.destroy(ctx)
            template3.result.destroy(ctx)
            template4.result.destroy(ctx)
            template5.result.destroy(ctx)
            template6.result.destroy(ctx)
            template7.result.destroy(ctx)
        asyncio.run(capnp.run(async_routine()))

    def run_test(self):
        self.run_echo_test()
        self.run_mining_test()

if __name__ == '__main__':
    IPCInterfaceTest(__file__).main()


Review comment (suggestion):
~In commit 504acfcd5d1ed4d77f7fd4f5dc57e66d6718d3d4:
If I apply this test independently before the miner.cpp code changes, it still passes, so not sure what we are testing here. Wouldn't this only be relevant if we'd run checkBlock on the template's own block? Afaict we only do checkBlock on blocks we re-create here.~

Code after:
            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()

            self.log.debug("First call checkBlock()")
            res = await mining.result.checkBlock(block.serialize(), check_opts)
            assert_equal(res.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())
            res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize_without_witness())
            assert_equal(res.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")
            res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
            assert_equal(res.result, True)

            self.log.debug("Block should propagate")
            assert_equal(self.nodes[1].getchaintips()[0]["height"], current_block_height + 1)
            # Stalls if a regression causes submitBlock() to accept an invalid block:
            self.sync_all()
            assert_equal(self.nodes[0].getchaintips()[0], self.nodes[1].getchaintips()[0])

            miniwallet.rescan_utxos()
            assert_equal(miniwallet.get_balance(), balance + 1)
            self.log.debug("Check block should fail now, since it is a duplicate")
            res = await mining.result.checkBlock(block.serialize(), check_opts)
            assert_equal(res.result, False)
            assert_equal(res.reason, "inconclusive-not-best-prevblk")