aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
authorAva Chow <github@achow101.com>2024-04-30 18:51:43 -0400
committerAva Chow <github@achow101.com>2024-04-30 18:59:56 -0400
commit326e563360671c568534ff72f45dec6b607e4b36 (patch)
tree7e373a3d04d75450fe6c2cf1f26e4fc9c2dc524f /src/net.cpp
parent0c3a3c9394e608c4beb92722ad034648af81dee7 (diff)
parent82f41d76f1c6ad38290917dad5499ffbe6b3974d (diff)
downloadbitcoin-326e563360671c568534ff72f45dec6b607e4b36.tar.xz
Merge bitcoin/bitcoin#28016: p2p: gives seednode priority over dnsseed if both are provided
82f41d76f1c6ad38290917dad5499ffbe6b3974d Added seednode prioritization message to help output (tdb3) 3120a4678ab2a71a381e847688f44068749cfa97 Gives seednode priority over dnsseed if both are provided (Sergi Delgado Segura) Pull request description: This is a follow-up of #27577 If both `seednode` and `dnsseed` are provided, the node will start a race between them in order to fetch data to feed the `addrman`. This PR gives priority to `seednode` over `dnsseed` so if some nodes are provided as seeds, they can be tried before defaulting to the `dnsseeds` ACKs for top commit: davidgumberg: untested reACK https://github.com/bitcoin/bitcoin/commit/82f41d76f1c6ad38290917dad5499ffbe6b3974d itornaza: tested re-ACK 82f41d76f1c6ad38290917dad5499ffbe6b3974d achow101: ACK 82f41d76f1c6ad38290917dad5499ffbe6b3974d cbergqvist: ACK 82f41d76f1c6ad38290917dad5499ffbe6b3974d Tree-SHA512: 4e39e10a7449af6cd9b8f9f6878f846b94bca11baf89ff2d4fbcd4f28293978a6ed71a3a86cea36d49eca891314c834e32af93f37a09c2cc698a878f84d31c62
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp209
1 files changed, 123 insertions, 86 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 98f2f4bad0..1eda98253a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2183,11 +2183,36 @@ void CConnman::WakeMessageHandler()
void CConnman::ThreadDNSAddressSeed()
{
+ constexpr int TARGET_OUTBOUND_CONNECTIONS = 2;
+ int outbound_connection_count = 0;
+
+ if (gArgs.IsArgSet("-seednode")) {
+ auto start = NodeClock::now();
+ constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
+ LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
+ while (!interruptNet) {
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
+ return;
+
+ // Abort if we have spent enough time without reaching our target.
+ // Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)
+ if (NodeClock::now() > start + SEEDNODE_TIMEOUT) {
+ LogPrintf("Couldn't connect to enough peers via seed nodes. Handing fetch logic to the DNS seeds.\n");
+ break;
+ }
+
+ outbound_connection_count = GetFullOutboundConnCount();
+ if (outbound_connection_count >= TARGET_OUTBOUND_CONNECTIONS) {
+ LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n");
+ break;
+ }
+ }
+ }
+
FastRandomContext rng;
std::vector<std::string> seeds = m_params.DNSSeeds();
Shuffle(seeds.begin(), seeds.end(), rng);
int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections
- int found = 0;
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
// When -forcednsseed is provided, query all.
@@ -2199,102 +2224,101 @@ void CConnman::ThreadDNSAddressSeed()
seeds_right_now = seeds.size();
}
- // goal: only query DNS seed if address need is acute
- // * If we have a reasonable number of peers in addrman, spend
- // some time trying them first. This improves user privacy by
- // creating fewer identifying DNS requests, reduces trust by
- // giving seeds less influence on the network topology, and
- // reduces traffic to the seeds.
- // * When querying DNS seeds query a few at once, this ensures
- // that we don't give DNS seeds the ability to eclipse nodes
- // that query them.
- // * If we continue having problems, eventually query all the
- // DNS seeds, and if that fails too, also try the fixed seeds.
- // (done in ThreadOpenConnections)
- const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
-
- for (const std::string& seed : seeds) {
- if (seeds_right_now == 0) {
- seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
-
- if (addrman.Size() > 0) {
- LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
- std::chrono::seconds to_wait = seeds_wait_time;
- while (to_wait.count() > 0) {
- // if sleeping for the MANY_PEERS interval, wake up
- // early to see if we have enough peers and can stop
- // this thread entirely freeing up its resources
- std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
- if (!interruptNet.sleep_for(w)) return;
- to_wait -= w;
-
- int nRelevant = 0;
- {
- LOCK(m_nodes_mutex);
- for (const CNode* pnode : m_nodes) {
- if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
- }
- }
- if (nRelevant >= 2) {
- if (found > 0) {
- LogPrintf("%d addresses found from DNS seeds\n", found);
- LogPrintf("P2P peers available. Finished DNS seeding.\n");
- } else {
- LogPrintf("P2P peers available. Skipped DNS seeding.\n");
+ // Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set
+ if (outbound_connection_count < TARGET_OUTBOUND_CONNECTIONS || seeds_right_now) {
+ // goal: only query DNS seed if address need is acute
+ // * If we have a reasonable number of peers in addrman, spend
+ // some time trying them first. This improves user privacy by
+ // creating fewer identifying DNS requests, reduces trust by
+ // giving seeds less influence on the network topology, and
+ // reduces traffic to the seeds.
+ // * When querying DNS seeds query a few at once, this ensures
+ // that we don't give DNS seeds the ability to eclipse nodes
+ // that query them.
+ // * If we continue having problems, eventually query all the
+ // DNS seeds, and if that fails too, also try the fixed seeds.
+ // (done in ThreadOpenConnections)
+ int found = 0;
+ const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
+
+ for (const std::string& seed : seeds) {
+ if (seeds_right_now == 0) {
+ seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
+
+ if (addrman.Size() > 0) {
+ LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
+ std::chrono::seconds to_wait = seeds_wait_time;
+ while (to_wait.count() > 0) {
+ // if sleeping for the MANY_PEERS interval, wake up
+ // early to see if we have enough peers and can stop
+ // this thread entirely freeing up its resources
+ std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
+ if (!interruptNet.sleep_for(w)) return;
+ to_wait -= w;
+
+ if (GetFullOutboundConnCount() >= TARGET_OUTBOUND_CONNECTIONS) {
+ if (found > 0) {
+ LogPrintf("%d addresses found from DNS seeds\n", found);
+ LogPrintf("P2P peers available. Finished DNS seeding.\n");
+ } else {
+ LogPrintf("P2P peers available. Skipped DNS seeding.\n");
+ }
+ return;
}
- return;
}
}
}
- }
-
- if (interruptNet) return;
- // hold off on querying seeds if P2P network deactivated
- if (!fNetworkActive) {
- LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
- do {
- if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
- } while (!fNetworkActive);
- }
+ if (interruptNet) return;
- LogPrintf("Loading addresses from DNS seed %s\n", seed);
- // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
- // for the base dns seed domain in chainparams
- if (HaveNameProxy()) {
- AddAddrFetch(seed);
- } else {
- std::vector<CAddress> vAdd;
- constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
- std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
- CNetAddr resolveSource;
- if (!resolveSource.SetInternal(host)) {
- continue;
+ // hold off on querying seeds if P2P network deactivated
+ if (!fNetworkActive) {
+ LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
+ do {
+ if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
+ } while (!fNetworkActive);
}
- // Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
- // one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
- // bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
- // returned.
- unsigned int nMaxIPs = 32;
- const auto addresses{LookupHost(host, nMaxIPs, true)};
- if (!addresses.empty()) {
- for (const CNetAddr& ip : addresses) {
- CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
- addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
- vAdd.push_back(addr);
- found++;
- }
- addrman.Add(vAdd, resolveSource);
- } else {
- // If the seed does not support a subdomain with our desired service bits,
- // we make an ADDR_FETCH connection to the DNS resolved peer address for the
- // base dns seed domain in chainparams
+
+ LogPrintf("Loading addresses from DNS seed %s\n", seed);
+ // If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
+ // for the base dns seed domain in chainparams
+ if (HaveNameProxy()) {
AddAddrFetch(seed);
+ } else {
+ std::vector<CAddress> vAdd;
+ constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
+ std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
+ CNetAddr resolveSource;
+ if (!resolveSource.SetInternal(host)) {
+ continue;
+ }
+ // Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
+ // one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
+ // bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
+ // returned.
+ unsigned int nMaxIPs = 32;
+ const auto addresses{LookupHost(host, nMaxIPs, true)};
+ if (!addresses.empty()) {
+ for (const CNetAddr& ip : addresses) {
+ CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
+ vAdd.push_back(addr);
+ found++;
+ }
+ addrman.Add(vAdd, resolveSource);
+ } else {
+ // If the seed does not support a subdomain with our desired service bits,
+ // we make an ADDR_FETCH connection to the DNS resolved peer address for the
+ // base dns seed domain in chainparams
+ AddAddrFetch(seed);
+ }
}
+ --seeds_right_now;
}
- --seeds_right_now;
+ LogPrintf("%d addresses found from DNS seeds\n", found);
+ } else {
+ LogPrintf("Skipping DNS seeds. Enough peers have been found\n");
}
- LogPrintf("%d addresses found from DNS seeds\n", found);
}
void CConnman::DumpAddresses()
@@ -2345,6 +2369,19 @@ void CConnman::StartExtraBlockRelayPeers()
m_start_extra_block_relay_peers = true;
}
+// Return the number of outbound connections that are full relay (not blocks only)
+int CConnman::GetFullOutboundConnCount() const
+{
+ int nRelevant = 0;
+ {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
+ if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
+ }
+ }
+ return nRelevant;
+}
+
// Return the number of peers we have over our outbound connection limit
// Exclude peers that are marked for disconnect, or are going to be
// disconnected soon (eg ADDR_FETCH and FEELER)