Repository: bitcoin/bitcoin
File: src/addrman.cpp (C++)

Code before:
    } else {
        search_tried = insecure_rand.randbool();
    }

    const int bucket_count{search_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT};

    // Loop through the addrman table until we find an appropriate entry
    double chance_factor = 1.0;
    while (1) {
        // Pick a bucket, and an initial position in that bucket.
        int bucket = insecure_rand.randrange(bucket_count);
        int initial_position = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);

        // Iterate over the positions of that bucket, starting at the initial one,
        // and looping around.
        int i, position, node_id;
        for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
            position = (initial_position + i) % ADDRMAN_BUCKET_SIZE;
            node_id = GetEntry(search_tried, bucket, position);
            if (node_id != -1) {
                if (network.has_value()) {
                    const auto it{mapInfo.find(node_id)};
                    if (Assume(it != mapInfo.end()) && it->second.GetNetwork() == *network) break;
                } else {
                    break;
                }
            }
        }

        // If the bucket is entirely empty, start over with a (likely) different one.
        if (i == ADDRMAN_BUCKET_SIZE) continue;

        // Find the entry to return.
        const auto it_found{mapInfo.find(node_id)};
        assert(it_found != mapInfo.end());
        const AddrInfo& info{it_found->second};

        // With probability GetChance() * chance_factor, return the entry.
        if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {
            LogDebug(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
            return {info, info.m_last_try};
        }

        // Otherwise start over with a (likely) different bucket, and increased chance factor.
        chance_factor *= 1.2;
    }
}

int AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const
{
    AssertLockHeld(cs);

Review comment (suggestion):
This code is correct, but is doing linear search in the list of networks. For values of up to 6 that is irrelevant, but if it is changed from `vector` to `unordered_set` then lookup is also shorter to write, in addition to being `O(1)`:

```suggestion
                    if (Assume(it != mapInfo.end()) && networks->contains(it->second.GetNetwork())) break;
```

Code after:
    bool search_tried;
    if (new_only || tried_count == 0) {
        search_tried = false;
    } else if (new_count == 0) {
        search_tried = true;
    } else {
        search_tried = insecure_rand.randbool();
    }

    const int bucket_count{search_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT};

    // Loop through the addrman table until we find an appropriate entry
    double chance_factor = 1.0;
    while (1) {
        // Pick a bucket, and an initial position in that bucket.
        int bucket = insecure_rand.randrange(bucket_count);
        int initial_position = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);

        // Iterate over the positions of that bucket, starting at the initial one,
        // and looping around.
        int i, position, node_id;
        for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
            position = (initial_position + i) % ADDRMAN_BUCKET_SIZE;
            node_id = GetEntry(search_tried, bucket, position);
            if (node_id != -1) {
                if (!networks.empty()) {
                    const auto it{mapInfo.find(node_id)};
                    if (Assume(it != mapInfo.end()) && networks.contains(it->second.GetNetwork())) break;
                } else {
                    break;
                }
            }
        }

        // If the bucket is entirely empty, start over with a (likely) different one.
        if (i == ADDRMAN_BUCKET_SIZE) continue;

        // Find the entry to return.
        const auto it_found{mapInfo.find(node_id)};
        assert(it_found != mapInfo.end());
        const AddrInfo& info{it_found->second};

        // With probability GetChance() * chance_factor, return the entry.
        if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {
            LogDebug(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
            return {info, info.m_last_try};
        }

        // Otherwise start over with a (likely) different bucket, and increased chance factor.
        chance_factor *= 1.2;
    }