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

Code before:
 * @param vBinds Vector of regular bind services (will be deduplicated)
 * @param onion_binds Vector of onion-specific bind services (will be deduplicated)
 * @return std::optional<CService> containing the first conflict found, or std::nullopt if no conflicts
 */
std::optional<CService> DeduplicateAndCheckBindingConflicts(
    std::vector<NetWhitebindPermissions>& vWhiteBinds,
    std::vector<CService>& vBinds,
    std::vector<CService>& onion_binds)
{
    // Step 1: Handle vWhiteBinds deduplication with special logic for permissions
    {
        std::map<CService, NetPermissionFlags> seen_whitebinds;
        std::vector<NetWhitebindPermissions> deduplicated;

        for (const auto& wb : vWhiteBinds) {
            auto it = seen_whitebinds.find(wb.m_service);
            if (it == seen_whitebinds.end()) {
                // First occurrence of this service
                seen_whitebinds[wb.m_service] = wb.m_flags;
                deduplicated.push_back(wb);
            } else if (it->second == wb.m_flags) {
                // Same service, same permissions - harmless duplicate, skip it
                continue;
            } else {
                // Same service, different permissions - conflict!
                return wb.m_service;
            }
        }
        vWhiteBinds = std::move(deduplicated);
    }

    // Step 2: Simple deduplication for vBinds
    {
        std::set<CService> seen;
        auto it = std::remove_if(vBinds.begin(), vBinds.end(),
            [&seen](const CService& service) {
                return !seen.insert(service).second;  // Remove if already seen
            });
        vBinds.erase(it, vBinds.end());
    }

    // Step 3: Simple deduplication for onion_binds
    {
        std::set<CService> seen;
        auto it = std::remove_if(onion_binds.begin(), onion_binds.end(),
            [&seen](const CService& service) {
                return !seen.insert(service).second;  // Remove if already seen
            });
        onion_binds.erase(it, onion_binds.end());
    }


Review comment (suggestion):
Since we don't expect this to happen often, I guess it's enough to stop at the first error instead of listing all 👍 

Code after:

    // Check all whitelisted bindings
    for (const auto& wb : conn_options.vWhiteBinds) {
        if (!seen.insert(wb.m_service).second) {
            return wb.m_service;
        }
    }

    // Check regular bindings
    for (const auto& bind : conn_options.vBinds) {
        if (!seen.insert(bind).second) {
            return bind;
        }
    }

    // Check onion bindings
    for (const auto& onion_bind : conn_options.onion_binds) {
        if (!seen.insert(onion_bind).second) {
            return onion_bind;
        }
    }

    return std::nullopt;
}

// A GUI user may opt to retry once with do_reindex set if there is a failure during chainstate initialization.
// The function therefore has to support re-entry.
static ChainstateLoadResult InitAndLoadChainstate(
    NodeContext& node,
    bool do_reindex,
    const bool do_reindex_chainstate,
    const kernel::CacheSizes& cache_sizes,
    const ArgsManager& args)
{
    // This function may be called twice, so any dirty state must be reset.
    node.notifications.reset(); // Drop state, such as a cached tip block
    node.mempool.reset();
    node.chainman.reset(); // Drop state, such as an initialized m_block_tree_db

    const CChainParams& chainparams = Params();

    Assert(!node.notifications); // Was reset above
    node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings));
    ReadNotificationArgs(args, *node.notifications);

    CTxMemPool::Options mempool_opts{
        .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
        .signals = node.validation_signals.get(),
    };
    Assert(ApplyArgsManOptions(args, chainparams, mempool_opts)); // no error can happen, already checked in AppInitParameterInteraction
    bilingual_str mempool_error;