# Buggy code
def _maybe_create_room_for_address(self, address: Address) -> None:
    if self._stop_event.ready():
        return None

    if self._get_room_for_address(address):
        return None

    assert self._raiden_service is not None, "_raiden_service not set"

    # The rooms creation is assymetric, only the node with the lower
    # address is responsible to create the room. This fixes race conditions
    # were the two nodes try to create a room with each other at the same
    # time, leading to communications problems if the nodes choose a
    # different room.
    #
    # This does not introduce a new attack vector, since not creating the
    # room is the same as being unresponsible.
    room_creator_address = my_place_or_yours(
        our_address=self._raiden_service.address, partner_address=address
    )
    if self._raiden_service.address != room_creator_address:
        self.log.debug(
            "This node should not create the room",
            partner_address=to_checksum_address(address),
        )
        return None

    with self.room_creation_lock[address]:
        candidates = self._client.search_user_directory(to_normalized_address(address))
        self._displayname_cache.warm_users(candidates)

        partner_users = [
            user for user in candidates if validate_userid_signature(user) == address
        ]
        partner_user_ids = [user.user_id for user in partner_users]

        if not partner_users:
            self.log.error(
                "Partner doesn't have a user",
                partner_address=to_checksum_address(address),
            )

            return None

        room = self._client.create_room(
            None, invitees=partner_user_ids, is_public=False
        )
        self.log.debug("Created private room", room=room, invitees=partner_users)

        self.log.debug(
            "Fetching room members",
            room=room,
            partner_address=to_checksum_address(address),
        )

        def partner_joined(fetched_members: List[User]) -> bool:
            if fetched_members is None:
                return False
            return any(member.user_id in partner_user_ids for member in fetched_members)

        members = self.retry_api_call(
            room.get_joined_members, verify_response=partner_joined, force_resync=True
        )

        assert members is not None, "fetching members failed"

        if not partner_joined(members):
            self.log.debug(
                "Peer has not joined from invite yet, should join eventually",
                room=room,
                partner_address=to_checksum_address(address),
                retry_interval=RETRY_INTERVAL,
            )

        # Here, the list of valid user ids is composed of
        # all known partner user ids along with our own.
        # If our partner roams, the user will be invited to
        # the room, resulting in multiple user ids for the partner.
        # If we roam, a new user and room will be created and only
        # the new user shall be in the room.
        valid_user_ids = partner_user_ids + [self._client.user_id]
        has_unexpected_user_ids = any(
            member.user_id not in valid_user_ids for member in members
        )

        if has_unexpected_user_ids:
            self._leave_unexpected_rooms(
                [room], "Private room has unexpected participants"
            )
            return None

        self._address_mgr.add_userids_for_address(
            address, {user.user_id for user in partner_users}
        )

        self._set_room_id_for_address(address, room.room_id)

        self.log.debug(
            "Channel room", peer_address=to_checksum_address(address), room=room
        )
        return room


# Traceback (ValueError)
Traceback (most recent call last):
File "src/gevent/greenlet.py", line 854, in gevent._greenlet.Greenlet.run
File "site-packages/raiden/network/transport/matrix/transport.py", line 629, in _health_check_worker
File "site-packages/raiden/network/transport/matrix/transport.py", line 606, in immediate_health_check_for
File "site-packages/raiden/network/transport/matrix/transport.py", line 577, in whitelist
File "site-packages/raiden/network/transport/matrix/transport.py", line 1194, in _maybe_create_room_for_address
File "site-packages/raiden/network/transport/matrix/utils.py", line 876, in my_place_or_yours
ValueError: Addresses to compare must differ
2020-02-19T14:55:13Z <Greenlet "Greenlet<fn:_health_check_worker>" at 0x7f1f5e02a050: <bound method MatrixTransport._health_check_worker of <MatrixTransport node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9 id:585de50e-f064-4a93-b3f4-df2bf40f8078>>> failed with ValueError

2020-02-19 14:55:13.088967 [error    ] Runnable subtask died!         [raiden.utils.runnable] exc=ValueError('Addresses to compare must differ') running=True subtask=<Greenlet "Greenlet<fn:_health_check_worker>" at 0x7f1f5e02a050: <bound method MatrixTransport._health_check_worker of <MatrixTransport node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9 id:585de50e-f064-4a93-b3f4-df2bf40f8078>>> this=<MatrixTransport node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9 id:585de50e-f064-4a93-b3f4-df2bf40f8078>
Traceback (most recent call last):
File "src/gevent/greenlet.py", line 854, in gevent._greenlet.Greenlet.run
File "site-packages/raiden/network/transport/matrix/transport.py", line 496, in _run
File "site-packages/raiden/network/transport/matrix/transport.py", line 718, in _broadcast_worker
File "src/gevent/event.py", line 133, in gevent._event.Event.wait
File "src/gevent/_abstract_linkable.py", line 208, in gevent.__abstract_linkable.AbstractLinkable._wait
File "src/gevent/_abstract_linkable.py", line 178, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_abstract_linkable.py", line 196, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_abstract_linkable.py", line 182, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 65, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/__greenlet_primitives.pxd", line 35, in gevent.__greenlet_primitives._greenlet_switch
ValueError: Addresses to compare must differ
2020-02-19T14:55:13Z <Greenlet "MatrixTransport._run node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9" at 0x7f1f5f9a3a70: _run> failed with ValueError

2020-02-19 14:55:13.259801 [error    ] Runnable subtask died!         [raiden.utils.runnable] exc=ValueError('Addresses to compare must differ') running=True subtask=<Greenlet "MatrixTransport._run node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9" at 0x7f1f5f9a3a70: _run> this=<RaidenService node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9>
Traceback (most recent call last):
File "src/gevent/greenlet.py", line 854, in gevent._greenlet.Greenlet.run
File "site-packages/raiden/raiden_service.py", line 375, in _run
File "src/gevent/event.py", line 133, in gevent._event.Event.wait
File "src/gevent/_abstract_linkable.py", line 208, in gevent.__abstract_linkable.AbstractLinkable._wait
File "src/gevent/_abstract_linkable.py", line 178, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_abstract_linkable.py", line 196, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_abstract_linkable.py", line 182, in gevent.__abstract_linkable.AbstractLinkable._wait_core
File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 61, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 65, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/__greenlet_primitives.pxd", line 35, in gevent.__greenlet_primitives._greenlet_switch
ValueError: Addresses to compare must differ
2020-02-19T14:55:13Z <Greenlet "RaidenService._run node:0x812f85143bdF6d28228FC580Ef649AA95ba6Fcd9" at 0x7f1f5f625b90: _run> failed with ValueError

FATAL: An unexpected exception occured. A traceback has been written to /tmp/raiden-exception-2020-02-19T14-5542cjz658.txt
Addresses to compare must differ
ReturnCode.FATAL

# Fixed code
def _maybe_create_room_for_address(self, address: Address) -> None:
    if self._stop_event.ready():
        return None

    if self._get_room_for_address(address):
        return None

    assert self._raiden_service is not None, "_raiden_service not set"

    # The rooms creation is asymmetric, only the node with the lower
    # address is responsible to create the room. This fixes race conditions
    # were the two nodes try to create a room with each other at the same
    # time, leading to communications problems if the nodes choose a
    # different room.
    #
    # This does not introduce a new attack vector, since not creating the
    # room is the same as being unresponsive.
    room_creator_address = my_place_or_yours(
        our_address=self._raiden_service.address, partner_address=address
    )
    if self._raiden_service.address != room_creator_address:
        self.log.debug(
            "This node should not create the room",
            partner_address=to_checksum_address(address),
        )
        return None

    with self.room_creation_lock[address]:
        candidates = self._client.search_user_directory(to_normalized_address(address))
        self._displayname_cache.warm_users(candidates)

        partner_users = [
            user for user in candidates if validate_userid_signature(user) == address
        ]
        partner_user_ids = [user.user_id for user in partner_users]

        if not partner_users:
            self.log.error(
                "Partner doesn't have a user",
                partner_address=to_checksum_address(address),
            )

            return None

        room = self._client.create_room(
            None, invitees=partner_user_ids, is_public=False
        )
        self.log.debug("Created private room", room=room, invitees=partner_users)

        self.log.debug(
            "Fetching room members",
            room=room,
            partner_address=to_checksum_address(address),
        )

        def partner_joined(fetched_members: List[User]) -> bool:
            if fetched_members is None:
                return False
            return any(member.user_id in partner_user_ids for member in fetched_members)

        members = self.retry_api_call(
            room.get_joined_members, verify_response=partner_joined, force_resync=True
        )

        assert members is not None, "fetching members failed"

        if not partner_joined(members):
            self.log.debug(
                "Peer has not joined from invite yet, should join eventually",
                room=room,
                partner_address=to_checksum_address(address),
                retry_interval=RETRY_INTERVAL,
            )

        # Here, the list of valid user ids is composed of
        # all known partner user ids along with our own.
        # If our partner roams, the user will be invited to
        # the room, resulting in multiple user ids for the partner.
        # If we roam, a new user and room will be created and only
        # the new user shall be in the room.
        valid_user_ids = partner_user_ids + [self._client.user_id]
        has_unexpected_user_ids = any(
            member.user_id not in valid_user_ids for member in members
        )

        if has_unexpected_user_ids:
            self._leave_unexpected_rooms(
                [room], "Private room has unexpected participants"
            )
            return None

        self._address_mgr.add_userids_for_address(
            address, {user.user_id for user in partner_users}
        )

        self._set_room_id_for_address(address, room.room_id)

        self.log.debug(
            "Channel room", peer_address=to_checksum_address(address), room=room
        )
        return room