diff --git a/src/net.cpp b/src/net.cpp index 960d0ee8412..ac4fa678f66 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1575,6 +1575,19 @@ int CConnman::GetExtraBlockRelayCount() const return std::max(block_relay_peers - m_max_outbound_block_relay, 0); } +std::unordered_set CConnman::GetReachableEmptyNetworks() const +{ + std::unordered_set networks{}; + for (int n = 0; n < NET_MAX; n++) { + enum Network net = (enum Network)n; + if (net == NET_UNROUTABLE || net == NET_INTERNAL) continue; + if (IsReachable(net) && addrman.Size(net, std::nullopt) == 0) { + networks.insert(net); + } + } + return networks; +} + void CConnman::ThreadOpenConnections(const std::vector connect) { SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION); @@ -1624,7 +1637,8 @@ void CConnman::ThreadOpenConnections(const std::vector connect) if (interruptNet) return; - if (add_fixed_seeds && addrman.size() == 0) { + const std::unordered_set fixed_seed_networks{GetReachableEmptyNetworks()}; + if (add_fixed_seeds && !fixed_seed_networks.empty()) { // When the node starts with an empty peers.dat, there are a few other sources of peers before // we fallback on to fixed seeds: -dnsseed, -seednode, -addnode // If none of those are available, we fallback on to fixed seeds immediately, else we allow @@ -1633,7 +1647,7 @@ void CConnman::ThreadOpenConnections(const std::vector connect) // It is cheapest to check if enough time has passed first. if (GetTime() > start + std::chrono::minutes{1}) { add_fixed_seeds_now = true; - LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty\n"); + LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n"); } // Checking !dnsseed is cheaper before locking 2 mutexes. @@ -1650,14 +1664,12 @@ void CConnman::ThreadOpenConnections(const std::vector connect) // We will not make outgoing connections to peers that are unreachable // (e.g. because of -onlynet configuration). // Therefore, we do not add them to addrman in the first place. - // Note that if you change -onlynet setting from one network to another, - // peers.dat will contain only peers of unreachable networks and - // manual intervention will be needed (either delete peers.dat after - // configuration change or manually add some reachable peer using addnode), - // see for details. + // In case previously unreachable networks become reachable + // (e.g. in case of -onlynet changes by the user), fixed seeds will + // be loaded only for networks for which we have no addressses. seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(), - [](const CAddress& addr) { return !IsReachable(addr); }), - seed_addrs.end()); + [&fixed_seed_networks](const CAddress& addr) { return fixed_seed_networks.count(addr.GetNetwork()) == 0; }), + seed_addrs.end()); CNetAddr local; local.SetInternal("fixedseeds"); addrman.Add(seed_addrs, local); diff --git a/src/net.h b/src/net.h index 31d17ea76cf..666e0f3b8a5 100644 --- a/src/net.h +++ b/src/net.h @@ -39,6 +39,7 @@ #include #include #include +#include #include class AddrMan; @@ -969,6 +970,12 @@ private: void RecordBytesRecv(uint64_t bytes); void RecordBytesSent(uint64_t bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex); + /** + Return reachable networks for which we have no addresses in addrman and therefore + may require loading fixed seeds. + */ + std::unordered_set GetReachableEmptyNetworks() const; + /** * Return vector of current BLOCK_RELAY peers. */