From c77c877a8e916878e09f64b2faa12eeca7528cc8 Mon Sep 17 00:00:00 2001 From: Martin Zumsande Date: Wed, 30 Nov 2022 15:55:22 -0500 Subject: [PATCH] net: Load fixed seeds from reachable networks for which we don't have addresses Previously, we'd only load fixed seeds if we'd not know any addresses at all. This change makes it possible to change -onlynet abruptly, e.g. from -onlynet=onion to -onlynet=i2p and still find peers. --- src/net.cpp | 30 +++++++++++++++++++++--------- src/net.h | 7 +++++++ 2 files changed, 28 insertions(+), 9 deletions(-) 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. */