# Buggy code
def __init__(
    self,
    transport: TransportAPI,
    base_protocol: BaseP2PProtocol,
    protocols: Sequence[ProtocolAPI],
    token: CancelToken = None,
    max_queue_size: int = 4096,
) -> None:
    if token is None:
        loop = None
    else:
        loop = token.loop
    base_token = CancelToken(f"multiplexer[{transport.remote}]", loop=loop)

    if token is None:
        self.cancel_token = base_token
    else:
        self.cancel_token = base_token.chain(token)

    self._transport = transport
    # the base `p2p` protocol instance.
    self._base_protocol = base_protocol

    # the sub-protocol instances
    self._protocols = protocols

    # Lock to ensure that multiple call sites cannot concurrently stream
    # messages.
    self._multiplex_lock = asyncio.Lock()

    # Lock management on a per-protocol basis to ensure we only have one
    # stream consumer for each protocol.
    self._protocol_locks = ResourceLock()

    # Each protocol gets a queue where messages for the individual protocol
    # are placed when streamed from the transport
    self._protocol_queues = {
        type(protocol): asyncio.Queue(max_queue_size)
        for protocol in self.get_protocols()
    }

    self._msg_counts = collections.defaultdict(int)


# Traceback (KeyError)
DEBUG  12-18 15:21:47  async_process_runner.py  b'\x1b[1m\x1b[31m   ERROR  2019-12-18 15:21:47,268           LESPeerPool  unexpected error during peer connection\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'Traceback (most recent call last):\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/peer_pool.py", line 209, in maybe_connect_more_peers\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    for backend in self.peer_backends\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/peer_pool.py", line 191, in _add_peers_from_backend\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    await self.connect_to_nodes(iter(candidates))\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/peer_pool.py", line 419, in connect_to_nodes\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    loop=self.get_event_loop(),\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/peer_pool.py", line 440, in connect_to_node\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    async with self.lock_node_for_handshake(node):\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/peer_pool.py", line 423, in lock_node_for_handshake\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    return self._handshake_locks.lock(node)\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/p2p/resource_lock.py", line 18, in lock\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    lock = self._locks[resource]\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'  File "/home/circleci/repo/.tox/py36-wheel-cli/lib/python3.6/weakref.py", line 394, in __getitem__\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b'    return self.data[ref(key)]\n'
DEBUG  12-18 15:21:47  async_process_runner.py  b"KeyError: <weakref at 0x7f48b9d9cf48; to 'Node' at 0x7f48b83175c0>\x1b[0m\n"

# Fixed code
def __init__(
    self,
    transport: TransportAPI,
    base_protocol: BaseP2PProtocol,
    protocols: Sequence[ProtocolAPI],
    token: CancelToken = None,
    max_queue_size: int = 4096,
) -> None:
    if token is None:
        loop = None
    else:
        loop = token.loop
    base_token = CancelToken(f"multiplexer[{transport.remote}]", loop=loop)

    if token is None:
        self.cancel_token = base_token
    else:
        self.cancel_token = base_token.chain(token)

    self._transport = transport
    # the base `p2p` protocol instance.
    self._base_protocol = base_protocol

    # the sub-protocol instances
    self._protocols = protocols

    # Lock to ensure that multiple call sites cannot concurrently stream
    # messages.
    self._multiplex_lock = asyncio.Lock()

    # Lock management on a per-protocol basis to ensure we only have one
    # stream consumer for each protocol.
    self._protocol_locks = {
        type(protocol): asyncio.Lock() for protocol in self.get_protocols()
    }

    # Each protocol gets a queue where messages for the individual protocol
    # are placed when streamed from the transport
    self._protocol_queues = {
        type(protocol): asyncio.Queue(max_queue_size)
        for protocol in self.get_protocols()
    }

    self._msg_counts = collections.defaultdict(int)