# Buggy code
async def _match_predictive_node_requests_to_peers(self) -> None:
    """
    Monitor for predictive nodes. These might be required by future blocks. They might not,
    because we run a speculative execution which might follow a different code path than
    the final block import does.

    When predictive nodes are queued up, ask the fastest available peasant (non-queen) peer
    for them. Without waiting for a response from the peer, continue and check if more
    predictive trie nodes are requested. Repeat indefinitely.
    """
    while self.manager.is_running:
        try:
            batch_id, hashes = await asyncio.wait_for(
                self._maybe_useful_nodes.get(eth_constants.MAX_STATE_FETCH),
                timeout=TOO_LONG_PREDICTIVE_PEER_DELAY,
            )
        except asyncio.TimeoutError:
            # Reduce the number of predictive peers, we seem to have plenty
            if self._min_predictive_peers > 0:
                self._min_predictive_peers -= 1
                self.logger.debug(
                    "Decremented predictive peers to %d",
                    self._min_predictive_peers,
                )
            # Re-attempt
            continue

        try:
            peer = await asyncio.wait_for(
                self._queen_tracker.pop_fastest_peasant(),
                timeout=TOO_LONG_PREDICTIVE_PEER_DELAY,
            )
        except asyncio.TimeoutError:
            # Increase the minimum number of predictive peers, we seem to not have enough
            new_predictive_peers = min(
                self._min_predictive_peers + 1,
                # Don't reserve more than half the peers for prediction
                self._num_peers // 2,
            )
            if new_predictive_peers != self._min_predictive_peers:
                self.logger.debug(
                    "Updating predictive peer count from %d to %d",
                    self._min_predictive_peers,
                    new_predictive_peers,
                )
                self._min_predictive_peers = new_predictive_peers

            # Prepare to restart
            await self._maybe_useful_nodes.complete(batch_id, ())
            continue

        self._num_predictive_requests_by_peer[peer] += 1
        self._predictive_requests += 1

        self.manager.run_task(
            self._get_predictive_nodes_from_peer,
            peer,
            hashes,
            batch_id,
        )


# Traceback (p2p.exceptions.ConnectionBusy)
f2b7-40b4-a77a-6ba6d13da819>: Timed out waiting for NodeDataV65 request lock or connection: Connection-<Session <Node(0xd4062d@91.13.194.238)> 1c231c61-f2b7-40b4-a77a-6ba6d13da819>�[0m
DEBUG  2020-09-02 12:59:58,686        BeamDownloader  Problem downloading nodes from peer, dropping...
Traceback (most recent call last):
File "/usr/src/app/trinity/p2p/exchange/candidate_stream.py", line 81, in payload_candidates
timeout=total_timeout * NUM_QUEUED_REQUESTS,
File "/usr/local/lib/python3.7/asyncio/tasks.py", line 449, in wait_for
raise futures.TimeoutError()
concurrent.futures._base.TimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/src/app/trinity/trinity/sync/beam/state.py", line 681, in _request_nodes
node_hashes, timeout=self._reply_timeout)
File "/usr/src/app/trinity/trinity/protocol/eth/exchanges.py", line 110, in __call__
timeout,
File "/usr/src/app/trinity/p2p/exchange/exchange.py", line 73, in get_result
timeout,
File "/usr/src/app/trinity/p2p/exchange/manager.py", line 59, in get_result
async for payload in stream.payload_candidates(request, tracker, timeout=timeout):
File "/usr/src/app/trinity/p2p/exchange/candidate_stream.py", line 85, in payload_candidates
f"Timed out waiting for {self.response_cmd_name} request lock "
p2p.exceptions.ConnectionBusy: Timed out waiting for NodeDataV65 request lock or connection: Connection-<Session <Node(0xd4062d@91.13.194.238)> 1c231c61-f2b7-40b4-a77a-6ba6d13da819>

# Fixed code
async def _match_predictive_node_requests_to_peers(self) -> None:
    """
    Monitor for predictive nodes. These might be required by future blocks. They might not,
    because we run a speculative execution which might follow a different code path than
    the final block import does.

    When predictive nodes are queued up, ask the fastest available peasant (non-queen) peer
    for them. Without waiting for a response from the peer, continue and check if more
    predictive trie nodes are requested. Repeat indefinitely.
    """
    while self.manager.is_running:
        try:
            batch_id, hashes = await asyncio.wait_for(
                self._maybe_useful_nodes.get(eth_constants.MAX_STATE_FETCH),
                timeout=TOO_LONG_PREDICTIVE_PEER_DELAY,
            )
        except asyncio.TimeoutError:
            # Reduce the number of predictive peers, we seem to have plenty
            if self._min_predictive_peers > 0:
                self._min_predictive_peers -= 1
                self.logger.debug(
                    "Decremented predictive peers to %d",
                    self._min_predictive_peers,
                )
            # Re-attempt
            continue

        try:
            peer = await asyncio.wait_for(
                self._queen_tracker.pop_fastest_peasant(),
                timeout=TOO_LONG_PREDICTIVE_PEER_DELAY,
            )
        except asyncio.TimeoutError:
            # Increase the minimum number of predictive peers, we seem to not have enough
            new_predictive_peers = min(
                self._min_predictive_peers + 1,
                # Don't reserve more than half the peers for prediction
                self._num_peers // 2,
            )
            if new_predictive_peers != self._min_predictive_peers:
                self.logger.debug(
                    "Updating predictive peer count from %d to %d",
                    self._min_predictive_peers,
                    new_predictive_peers,
                )
                self._min_predictive_peers = new_predictive_peers

            cancel_attempt = True
        else:
            if peer.eth_api.get_node_data.is_requesting:
                self.logger.debug(
                    "Want predictive nodes from %s, but it has an active request, skipping...",
                    peer,
                )
                self._queen_tracker.insert_peer(peer, NON_IDEAL_RESPONSE_PENALTY)
                cancel_attempt = True
            else:
                cancel_attempt = False

        if cancel_attempt:
            # Prepare to restart
            await self._maybe_useful_nodes.complete(batch_id, ())
            continue

        self._num_predictive_requests_by_peer[peer] += 1
        self._predictive_requests += 1

        self.manager.run_task(
            self._get_predictive_nodes_from_peer,
            peer,
            hashes,
            batch_id,
        )