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

Code before:
        super().setup_nodes()
        # Use this function to also load the capnp modules (we cannot use set_test_params for this,
        # as it is being called before knowing whether capnp is available).
        self.capnp_modules = self.load_capnp_modules()

    async def make_capnp_init_ctx(self):
        node = self.nodes[0]
        # Establish a connection, and create Init proxy object.
        connection = await capnp.AsyncIoStream.create_unix_connection(node.ipc_socket_path)
        client = capnp.TwoPartyClient(connection)
        init = client.bootstrap().cast_as(self.capnp_modules['init'].Init)
        # Create a remote thread on the server for the IPC calls to be executed in.
        threadmap = init.construct().threadMap
        thread = threadmap.makeThread("pythread").result
        ctx = self.capnp_modules['proxy'].Context()
        ctx.thread = thread
        # Return both.
        return ctx, init

    async def parse_and_deserialize_block(self, block_template, ctx):
        block_data = BytesIO((await block_template.getBlock(ctx)).result)
        block = CBlock()
        block.deserialize(block_data)
        return block

    async def get_coinbase_raw_tx(self, block_template, ctx):
        assert block_template is not None
        coinbase_data = BytesIO((await block_template.getCoinbaseRawTx(ctx)).result)
        tx = CTransaction()
        tx.deserialize(coinbase_data)
        return tx

    async def parse_and_deserialize_coinbase(self, block_template, ctx) -> CoinbaseTxData:
        assert block_template is not None
        # Note: the template_capnp struct will be garbage-collected when this
        # method returns, so it is important to copy any Data fields from it
        # which need to be accessed later using the bytes() cast. Starting with
        # pycapnp v2.2.0, Data fields have type `memoryview` and are ephemeral.
        template_capnp = (await block_template.getCoinbaseTx(ctx)).result
        witness: Optional[bytes] = None
        if template_capnp._has("witness"):
            witness = bytes(template_capnp.witness)
        return CoinbaseTxData(
            version=int(template_capnp.version),
            sequence=int(template_capnp.sequence),
            scriptSigPrefix=bytes(template_capnp.scriptSigPrefix),
            witness=witness,
            blockRewardRemaining=int(template_capnp.blockRewardRemaining),
            requiredOutputs=[bytes(output) for output in template_capnp.requiredOutputs],
            lockTime=int(template_capnp.lockTime),
        )

Review comment (suggestion):
In commit "test: clarify getCoinbaseRawTx() comparison" (bf3b5d6d069a0bbb39af0c487fd597257f862f31)

Looking around here it would be nice IMO to rename `parse_and_deserialize_block` to `get_block` and `parse_and_deserialize_coinbase` to `get_coinbase` as well. Existing names are hard to read and look like they are doing they are doing local parsing and deserializing when actually they are making remote calls.

Code after:
        self.num_nodes = 2

    def setup_nodes(self):
        self.extra_init = [{"ipcbind": True}, {}]
        super().setup_nodes()
        # Use this function to also load the capnp modules (we cannot use set_test_params for this,
        # as it is being called before knowing whether capnp is available).
        self.capnp_modules = self.load_capnp_modules()

    async def make_capnp_init_ctx(self):
        node = self.nodes[0]
        # Establish a connection, and create Init proxy object.
        connection = await capnp.AsyncIoStream.create_unix_connection(node.ipc_socket_path)
        client = capnp.TwoPartyClient(connection)
        init = client.bootstrap().cast_as(self.capnp_modules['init'].Init)
        # Create a remote thread on the server for the IPC calls to be executed in.
        threadmap = init.construct().threadMap
        thread = threadmap.makeThread("pythread").result
        ctx = self.capnp_modules['proxy'].Context()
        ctx.thread = thread
        # Return both.
        return ctx, init

    async def parse_and_deserialize_block(self, block_template, ctx):
        block_data = BytesIO((await block_template.getBlock(ctx)).result)
        block = CBlock()
        block.deserialize(block_data)
        return block

    async def get_coinbase_raw_tx(self, block_template, ctx):
        assert block_template is not None
        coinbase_data = BytesIO((await block_template.getCoinbaseRawTx(ctx)).result)
        tx = CTransaction()
        tx.deserialize(coinbase_data)
        return tx

    async def parse_and_deserialize_coinbase(self, block_template, ctx) -> CoinbaseTxData:
        assert block_template is not None
        # Note: the template_capnp struct will be garbage-collected when this
        # method returns, so it is important to copy any Data fields from it
        # which need to be accessed later using the bytes() cast. Starting with
        # pycapnp v2.2.0, Data fields have type `memoryview` and are ephemeral.
        template_capnp = (await block_template.getCoinbaseTx(ctx)).result
        witness: Optional[bytes] = None
        if template_capnp._has("witness"):
            witness = bytes(template_capnp.witness)
        return CoinbaseTxData(
            version=int(template_capnp.version),
            sequence=int(template_capnp.sequence),
            scriptSigPrefix=bytes(template_capnp.scriptSigPrefix),
            witness=witness,