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

Code before:
}

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

    if (use_tried) {
        if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_TRIED_BUCKET_COUNT)) {
            return vvTried[bucket][position];
        }
    } else {
        if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_NEW_BUCKET_COUNT)) {
            return vvNew[bucket][position];
        }
    }

    return -1;
}

std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
    AssertLockHeld(cs);

    size_t nNodes = vRandom.size();
    if (max_pct != 0) {
        nNodes = max_pct * nNodes / 100;
    }
    if (max_addresses != 0) {
        nNodes = std::min(nNodes, max_addresses);
    }

    // gather a list of random nodes, skipping those of low quality
    const auto now{Now<NodeSeconds>()};
    std::vector<CAddress> addresses;
    addresses.reserve(nNodes);
    for (unsigned int n = 0; n < vRandom.size(); n++) {
        if (addresses.size() >= nNodes)
            break;

        int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
        SwapRandom(n, nRndPos);
        const auto it{mapInfo.find(vRandom[n])};
        assert(it != mapInfo.end());

        const AddrInfo& ai{it->second};

        // Filter by network (optional)
        if (network != std::nullopt && ai.GetNetClass() != network) continue;

        // Filter for quality
        if (ai.IsTerrible(now) && filtered) continue;

Review comment (bug):
Since there was a bug somewhere if we ever pass `max_pct > 100` (with privacy implications, the reason `max_pct` exists is not to reveal the entire addrman), why not `Assume(max_pct <=100)` / adjust the fuzzer range instead of trying to accommodate it? There is a difference between `max_pct` and the `max_addresses` where a caller could legitimately ask for more addresses than addrman has because they don't know current addrman size - no caller should ever ask for more than 100%.

Code after:
}

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

    if (use_tried) {
        if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_TRIED_BUCKET_COUNT)) {
            return vvTried[bucket][position];
        }
    } else {
        if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_NEW_BUCKET_COUNT)) {
            return vvNew[bucket][position];
        }
    }

    return -1;
}

std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const
{
    AssertLockHeld(cs);
    Assume(max_pct <= 100);

    size_t nNodes = vRandom.size();
    if (max_pct != 0) {
        max_pct = std::min(max_pct, size_t{100});
        nNodes = max_pct * nNodes / 100;
    }
    if (max_addresses != 0) {
        nNodes = std::min(nNodes, max_addresses);
    }

    // gather a list of random nodes, skipping those of low quality
    const auto now{Now<NodeSeconds>()};
    std::vector<CAddress> addresses;
    addresses.reserve(nNodes);
    for (unsigned int n = 0; n < vRandom.size(); n++) {
        if (addresses.size() >= nNodes)
            break;

        int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
        SwapRandom(n, nRndPos);
        const auto it{mapInfo.find(vRandom[n])};
        assert(it != mapInfo.end());

        const AddrInfo& ai{it->second};

        // Filter by network (optional)
        if (network != std::nullopt && ai.GetNetClass() != network) continue;