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

Code before:
        coroutine = cls.create_listen_server(addr, port, callback, p2p)
        cls.network_event_loop.call_soon_threadsafe(cls.network_event_loop.create_task, coroutine)

    @classmethod
    async def create_listen_server(cls, addr, port, callback, proto):
        def peer_protocol():
            """Returns a function that does the protocol handling for a new
            connection. To allow different connections to have different
            behaviors, the protocol function is first put in the cls.protos
            dict. When the connection is made, the function removes the
            protocol function from that dict, and returns it so the event loop
            can start executing it."""
            response = cls.protos.get((addr, port))
            # remove protocol function from dict only when reconnection doesn't need to happen/already happened
            if not proto.reconnect:
                cls.protos[(addr, port)] = None
            return response

        if (addr, port) not in cls.listeners:
            # When creating a listener on a given (addr, port) we only need to
            # do it once. If we want different behaviors for different
            # connections, we can accomplish this by providing different
            # `proto` functions

            listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
            # When port=0, the OS assigns an available ephemeral port. Retrieve
            # the actual port so callers know where the server is listening.
            actual_port = listener.sockets[0].getsockname()[1]
            logger.debug("Listening server on %s:%d should be started" % (addr, actual_port))
            cls.listeners[(addr, actual_port)] = listener
            port = actual_port

        cls.protos[(addr, port)] = proto
        callback(addr, port)


class P2PDataStore(P2PInterface):
    """A P2P data store class.

    Keeps a block and transaction store and responds correctly to getdata and getheaders requests."""

    def __init__(self):
        super().__init__()
        # store of blocks. key is block hash, value is a CBlock object
        self.block_store = {}
        self.last_block_hash = ''
        # store of txs. key is txid, value is a CTransaction object
        self.tx_store = {}
        self.getdata_requests = []

    def on_getdata(self, message):

Review comment (bug):
nit, feel free to ignore, I think the current diff

```diff
             listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
-            logger.debug("Listening server on %s:%d should be started" % (addr, port))
-            cls.listeners[(addr, port)] = listener
+            # When port=0, the OS assigns an available ephemeral port. Retrieve
+            # the actual port so callers know where the server is listening.
+            actual_port = listener.sockets[0].getsockname()[1]
+            logger.debug("Listening server on %s:%d should be started" % (addr, actual_port))
+            cls.listeners[(addr, actual_port)] = listener
+            port = actual_port
```
is equivalent to:
```diff
             listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
+            port = listener.sockets[0].getsockname()[1]
             logger.debug("Listening server on %s:%d should be started" % (addr, port))
             cls.listeners[(addr, port)] = listener
```

Code after:
        coroutine = cls.create_listen_server(addr, port, callback, p2p)
        cls.network_event_loop.call_soon_threadsafe(cls.network_event_loop.create_task, coroutine)

    @classmethod
    async def create_listen_server(cls, addr, port, callback, proto):
        def peer_protocol():
            """Returns a function that does the protocol handling for a new
            connection. To allow different connections to have different
            behaviors, the protocol function is first put in the cls.protos
            dict. When the connection is made, the function removes the
            protocol function from that dict, and returns it so the event loop
            can start executing it."""
            response = cls.protos.get((addr, port))
            # remove protocol function from dict only when reconnection doesn't need to happen/already happened
            if not proto.reconnect:
                cls.protos[(addr, port)] = None
            return response

        if port == 0 or (addr, port) not in cls.listeners:
            # When creating a listener on a given (addr, port) we only need to
            # do it once. If we want different behaviors for different
            # connections, we can accomplish this by providing different
            # `proto` functions

            listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
            port = listener.sockets[0].getsockname()[1]
            logger.debug("Listening server on %s:%d should be started" % (addr, port))
            cls.listeners[(addr, port)] = listener

        cls.protos[(addr, port)] = proto
        callback(addr, port)


class P2PDataStore(P2PInterface):
    """A P2P data store class.

    Keeps a block and transaction store and responds correctly to getdata and getheaders requests."""

    def __init__(self):
        super().__init__()
        # store of blocks. key is block hash, value is a CBlock object
        self.block_store = {}
        self.last_block_hash = ''
        # store of txs. key is txid, value is a CTransaction object
        self.tx_store = {}
        self.getdata_requests = []

    def on_getdata(self, message):
        """Check for the tx/block in our stores and if found, reply with MSG_TX or MSG_BLOCK."""
        for inv in message.inv:
            self.getdata_requests.append(inv.hash)