# Buggy code
def monitor_downloads(self, dslist):
    # Monitor downloads with anonymous flag set, and build rendezvous/introduction points when needed.
    new_states = {}
    hops = {}

    for ds in dslist:
        download = ds.get_download()
        if download.get_hops() > 0:
            # Convert the real infohash to the infohash used for looking up introduction points
            real_info_hash = download.get_def().get_infohash()
            info_hash = self.get_lookup_info_hash(real_info_hash)
            hops[info_hash] = download.get_hops()
            new_states[info_hash] = ds.get_status()

    self.hops = hops

    for info_hash in set(new_states.keys() + self.download_states.keys()):
        new_state = new_states.get(info_hash, None)
        old_state = self.download_states.get(info_hash, None)
        state_changed = new_state != old_state

        # If the introducing circuit does not exist anymore or timed out: Build a new circuit
        if info_hash in self.infohash_ip_circuits:
            for circuit_id, time_created in self.infohash_ip_circuits[info_hash]:
                if (
                    circuit_id not in self.my_intro_points
                    and time_created < time.time() - 30
                ):
                    self.infohash_ip_circuits[info_hash].remove(
                        (circuit_id, time_created)
                    )
                    if self.notifier:
                        self.notifier.notify(
                            NTFY_TUNNEL,
                            NTFY_IP_RECREATE,
                            circuit_id,
                            info_hash.encode("hex")[:6],
                        )
                    self.tunnel_logger.info(
                        "Recreate the introducing circuit for %s"
                        % info_hash.encode("hex")
                    )
                    self.create_introduction_point(info_hash)

        time_elapsed = time.time() - self.last_dht_lookup.get(info_hash, 0)
        force_dht_lookup = time_elapsed >= self.settings.dht_lookup_interval
        if state_changed or force_dht_lookup:
            self.tunnel_logger.info(
                "Do dht lookup to find hidden services peers for %s"
                % info_hash.encode("hex")
            )
            self.do_dht_lookup(info_hash)

        if state_changed and new_state == DLSTATUS_SEEDING:
            self.create_introduction_point(info_hash)

        elif state_changed and new_state in [DLSTATUS_STOPPED, None]:
            if info_hash in self.infohash_pex:
                self.infohash_pex.pop(info_hash)

            for cid, info_hash_hops in self.my_download_points.items():
                if info_hash_hops[0] == info_hash:
                    self.remove_circuit(cid, "download stopped", destroy=True)

            for cid, info_hash_list in self.my_intro_points.items():
                for i in xrange(len(info_hash_list) - 1, -1, -1):
                    if info_hash_list[i] == info_hash:
                        info_hash_list.pop(i)

                if len(info_hash_list) == 0:
                    self.remove_circuit(cid, "all downloads stopped", destroy=True)

    self.download_states = new_states


# Traceback (KeyError)
Traceback (most recent call last):
File "/var/data/projects/delft/tribler/Tribler/Main/tribler_main.py", line 646, in sesscb_states_callback
self.tunnel_community.monitor_downloads(dslist)
File "/var/data/projects/delft/tribler/Tribler/dispersy/util.py", line 35, in helper
return func(*args, **kargs)
File "/var/data/projects/delft/tribler/Tribler/community/tunnel/hidden_community.py", line 256, in monitor_downloads
self.do_dht_lookup(info_hash)
File "/var/data/projects/delft/tribler/Tribler/community/tunnel/hidden_community.py", line 282, in do_dht_lookup
circuit = self.selection_strategy.select(None, self.hops[info_hash])
KeyError: '%U\x9bd\x04\x9d\xcagZc3\\\xaa\x8bZ\xaa\x91\x0e/\x04'

# Fixed code
def monitor_downloads(self, dslist):
    # Monitor downloads with anonymous flag set, and build rendezvous/introduction points when needed.
    new_states = {}
    hops = {}

    for ds in dslist:
        download = ds.get_download()
        if download.get_hops() > 0:
            # Convert the real infohash to the infohash used for looking up introduction points
            real_info_hash = download.get_def().get_infohash()
            info_hash = self.get_lookup_info_hash(real_info_hash)
            hops[info_hash] = download.get_hops()
            new_states[info_hash] = ds.get_status()

    self.hops = hops

    for info_hash in set(new_states.keys() + self.download_states.keys()):
        new_state = new_states.get(info_hash, None)
        old_state = self.download_states.get(info_hash, None)
        state_changed = new_state != old_state

        # If the introducing circuit does not exist anymore or timed out: Build a new circuit
        if info_hash in self.infohash_ip_circuits:
            for circuit_id, time_created in self.infohash_ip_circuits[info_hash]:
                if (
                    circuit_id not in self.my_intro_points
                    and time_created < time.time() - 30
                ):
                    self.infohash_ip_circuits[info_hash].remove(
                        (circuit_id, time_created)
                    )
                    if self.notifier:
                        self.notifier.notify(
                            NTFY_TUNNEL,
                            NTFY_IP_RECREATE,
                            circuit_id,
                            info_hash.encode("hex")[:6],
                        )
                    self.tunnel_logger.info(
                        "Recreate the introducing circuit for %s"
                        % info_hash.encode("hex")
                    )
                    self.create_introduction_point(info_hash)

        time_elapsed = time.time() - self.last_dht_lookup.get(info_hash, 0)
        force_dht_lookup = time_elapsed >= self.settings.dht_lookup_interval
        if (state_changed or force_dht_lookup) and (
            new_state == DLSTATUS_SEEDING or new_state == DLSTATUS_DOWNLOADING
        ):
            self.tunnel_logger.info(
                "Do dht lookup to find hidden services peers for %s"
                % info_hash.encode("hex")
            )
            self.do_dht_lookup(info_hash)

        if state_changed and new_state == DLSTATUS_SEEDING:
            self.create_introduction_point(info_hash)

        elif state_changed and new_state in [DLSTATUS_STOPPED, None]:
            if info_hash in self.infohash_pex:
                self.infohash_pex.pop(info_hash)

            for cid, info_hash_hops in self.my_download_points.items():
                if info_hash_hops[0] == info_hash:
                    self.remove_circuit(cid, "download stopped", destroy=True)

            for cid, info_hash_list in self.my_intro_points.items():
                for i in xrange(len(info_hash_list) - 1, -1, -1):
                    if info_hash_list[i] == info_hash:
                        info_hash_list.pop(i)

                if len(info_hash_list) == 0:
                    self.remove_circuit(cid, "all downloads stopped", destroy=True)

    self.download_states = new_states