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

Code before:
    // 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());
    }

    // Step 4: Check for cross-vector conflicts
    // Build sets for efficient lookup
    std::set<CService> whitebind_services;
    for (const auto& wb : vWhiteBinds) {
        whitebind_services.insert(wb.m_service);
    }

    // Check if any service from vBinds exists in vWhiteBinds
    for (const auto& bind : vBinds) {

Review comment (suggestion):
nit:
```suggestion
        auto it = std::ranges::remove_if(onion_binds,
```

Code after:
    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;
    Assert(!node.mempool); // Was reset above
    node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
    if (!mempool_error.empty()) {
        return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error};
    }
    LogInfo("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)",
            cache_sizes.coins * (1.0 / 1024 / 1024),
            mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
    ChainstateManager::Options chainman_opts{