Skip to content

Commit 326e563

Browse files
committed
Merge bitcoin/bitcoin#28016: p2p: gives seednode priority over dnsseed if both are provided
82f41d7 Added seednode prioritization message to help output (tdb3) 3120a46 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 bitcoin/bitcoin@82f41d7 itornaza: tested re-ACK 82f41d7 achow101: ACK 82f41d7 cbergqvist: ACK 82f41d7 Tree-SHA512: 4e39e10a7449af6cd9b8f9f6878f846b94bca11baf89ff2d4fbcd4f28293978a6ed71a3a86cea36d49eca891314c834e32af93f37a09c2cc698a878f84d31c62
2 parents 0c3a3c9 + 82f41d7 commit 326e563

File tree

3 files changed

+126
-87
lines changed

3 files changed

+126
-87
lines changed

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ void SetupServerArgs(ArgsManager& argsman)
544544
argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION);
545545
#endif
546546
argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
547-
argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
547+
argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes. During startup, seednodes will be tried before dnsseeds.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
548548
argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
549549
argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
550550
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);

src/net.cpp

Lines changed: 123 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,11 +2183,36 @@ void CConnman::WakeMessageHandler()
21832183

21842184
void CConnman::ThreadDNSAddressSeed()
21852185
{
2186+
constexpr int TARGET_OUTBOUND_CONNECTIONS = 2;
2187+
int outbound_connection_count = 0;
2188+
2189+
if (gArgs.IsArgSet("-seednode")) {
2190+
auto start = NodeClock::now();
2191+
constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
2192+
LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
2193+
while (!interruptNet) {
2194+
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
2195+
return;
2196+
2197+
// Abort if we have spent enough time without reaching our target.
2198+
// Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)
2199+
if (NodeClock::now() > start + SEEDNODE_TIMEOUT) {
2200+
LogPrintf("Couldn't connect to enough peers via seed nodes. Handing fetch logic to the DNS seeds.\n");
2201+
break;
2202+
}
2203+
2204+
outbound_connection_count = GetFullOutboundConnCount();
2205+
if (outbound_connection_count >= TARGET_OUTBOUND_CONNECTIONS) {
2206+
LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n");
2207+
break;
2208+
}
2209+
}
2210+
}
2211+
21862212
FastRandomContext rng;
21872213
std::vector<std::string> seeds = m_params.DNSSeeds();
21882214
Shuffle(seeds.begin(), seeds.end(), rng);
21892215
int seeds_right_now = 0; // Number of seeds left before testing if we have enough connections
2190-
int found = 0;
21912216

21922217
if (gArgs.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED)) {
21932218
// When -forcednsseed is provided, query all.
@@ -2199,102 +2224,101 @@ void CConnman::ThreadDNSAddressSeed()
21992224
seeds_right_now = seeds.size();
22002225
}
22012226

2202-
// goal: only query DNS seed if address need is acute
2203-
// * If we have a reasonable number of peers in addrman, spend
2204-
// some time trying them first. This improves user privacy by
2205-
// creating fewer identifying DNS requests, reduces trust by
2206-
// giving seeds less influence on the network topology, and
2207-
// reduces traffic to the seeds.
2208-
// * When querying DNS seeds query a few at once, this ensures
2209-
// that we don't give DNS seeds the ability to eclipse nodes
2210-
// that query them.
2211-
// * If we continue having problems, eventually query all the
2212-
// DNS seeds, and if that fails too, also try the fixed seeds.
2213-
// (done in ThreadOpenConnections)
2214-
const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
2215-
2216-
for (const std::string& seed : seeds) {
2217-
if (seeds_right_now == 0) {
2218-
seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
2219-
2220-
if (addrman.Size() > 0) {
2221-
LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
2222-
std::chrono::seconds to_wait = seeds_wait_time;
2223-
while (to_wait.count() > 0) {
2224-
// if sleeping for the MANY_PEERS interval, wake up
2225-
// early to see if we have enough peers and can stop
2226-
// this thread entirely freeing up its resources
2227-
std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
2228-
if (!interruptNet.sleep_for(w)) return;
2229-
to_wait -= w;
2230-
2231-
int nRelevant = 0;
2232-
{
2233-
LOCK(m_nodes_mutex);
2234-
for (const CNode* pnode : m_nodes) {
2235-
if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
2236-
}
2237-
}
2238-
if (nRelevant >= 2) {
2239-
if (found > 0) {
2240-
LogPrintf("%d addresses found from DNS seeds\n", found);
2241-
LogPrintf("P2P peers available. Finished DNS seeding.\n");
2242-
} else {
2243-
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
2227+
// Proceed with dnsseeds if seednodes hasn't reached the target or if forcednsseed is set
2228+
if (outbound_connection_count < TARGET_OUTBOUND_CONNECTIONS || seeds_right_now) {
2229+
// goal: only query DNS seed if address need is acute
2230+
// * If we have a reasonable number of peers in addrman, spend
2231+
// some time trying them first. This improves user privacy by
2232+
// creating fewer identifying DNS requests, reduces trust by
2233+
// giving seeds less influence on the network topology, and
2234+
// reduces traffic to the seeds.
2235+
// * When querying DNS seeds query a few at once, this ensures
2236+
// that we don't give DNS seeds the ability to eclipse nodes
2237+
// that query them.
2238+
// * If we continue having problems, eventually query all the
2239+
// DNS seeds, and if that fails too, also try the fixed seeds.
2240+
// (done in ThreadOpenConnections)
2241+
int found = 0;
2242+
const std::chrono::seconds seeds_wait_time = (addrman.Size() >= DNSSEEDS_DELAY_PEER_THRESHOLD ? DNSSEEDS_DELAY_MANY_PEERS : DNSSEEDS_DELAY_FEW_PEERS);
2243+
2244+
for (const std::string& seed : seeds) {
2245+
if (seeds_right_now == 0) {
2246+
seeds_right_now += DNSSEEDS_TO_QUERY_AT_ONCE;
2247+
2248+
if (addrman.Size() > 0) {
2249+
LogPrintf("Waiting %d seconds before querying DNS seeds.\n", seeds_wait_time.count());
2250+
std::chrono::seconds to_wait = seeds_wait_time;
2251+
while (to_wait.count() > 0) {
2252+
// if sleeping for the MANY_PEERS interval, wake up
2253+
// early to see if we have enough peers and can stop
2254+
// this thread entirely freeing up its resources
2255+
std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
2256+
if (!interruptNet.sleep_for(w)) return;
2257+
to_wait -= w;
2258+
2259+
if (GetFullOutboundConnCount() >= TARGET_OUTBOUND_CONNECTIONS) {
2260+
if (found > 0) {
2261+
LogPrintf("%d addresses found from DNS seeds\n", found);
2262+
LogPrintf("P2P peers available. Finished DNS seeding.\n");
2263+
} else {
2264+
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
2265+
}
2266+
return;
22442267
}
2245-
return;
22462268
}
22472269
}
22482270
}
2249-
}
2250-
2251-
if (interruptNet) return;
22522271

2253-
// hold off on querying seeds if P2P network deactivated
2254-
if (!fNetworkActive) {
2255-
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
2256-
do {
2257-
if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
2258-
} while (!fNetworkActive);
2259-
}
2272+
if (interruptNet) return;
22602273

2261-
LogPrintf("Loading addresses from DNS seed %s\n", seed);
2262-
// If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
2263-
// for the base dns seed domain in chainparams
2264-
if (HaveNameProxy()) {
2265-
AddAddrFetch(seed);
2266-
} else {
2267-
std::vector<CAddress> vAdd;
2268-
constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
2269-
std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
2270-
CNetAddr resolveSource;
2271-
if (!resolveSource.SetInternal(host)) {
2272-
continue;
2274+
// hold off on querying seeds if P2P network deactivated
2275+
if (!fNetworkActive) {
2276+
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
2277+
do {
2278+
if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
2279+
} while (!fNetworkActive);
22732280
}
2274-
// Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
2275-
// one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
2276-
// bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
2277-
// returned.
2278-
unsigned int nMaxIPs = 32;
2279-
const auto addresses{LookupHost(host, nMaxIPs, true)};
2280-
if (!addresses.empty()) {
2281-
for (const CNetAddr& ip : addresses) {
2282-
CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
2283-
addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
2284-
vAdd.push_back(addr);
2285-
found++;
2286-
}
2287-
addrman.Add(vAdd, resolveSource);
2288-
} else {
2289-
// If the seed does not support a subdomain with our desired service bits,
2290-
// we make an ADDR_FETCH connection to the DNS resolved peer address for the
2291-
// base dns seed domain in chainparams
2281+
2282+
LogPrintf("Loading addresses from DNS seed %s\n", seed);
2283+
// If -proxy is in use, we make an ADDR_FETCH connection to the DNS resolved peer address
2284+
// for the base dns seed domain in chainparams
2285+
if (HaveNameProxy()) {
22922286
AddAddrFetch(seed);
2287+
} else {
2288+
std::vector<CAddress> vAdd;
2289+
constexpr ServiceFlags requiredServiceBits{SeedsServiceFlags()};
2290+
std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
2291+
CNetAddr resolveSource;
2292+
if (!resolveSource.SetInternal(host)) {
2293+
continue;
2294+
}
2295+
// Limit number of IPs learned from a single DNS seed. This limit exists to prevent the results from
2296+
// one DNS seed from dominating AddrMan. Note that the number of results from a UDP DNS query is
2297+
// bounded to 33 already, but it is possible for it to use TCP where a larger number of results can be
2298+
// returned.
2299+
unsigned int nMaxIPs = 32;
2300+
const auto addresses{LookupHost(host, nMaxIPs, true)};
2301+
if (!addresses.empty()) {
2302+
for (const CNetAddr& ip : addresses) {
2303+
CAddress addr = CAddress(CService(ip, m_params.GetDefaultPort()), requiredServiceBits);
2304+
addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
2305+
vAdd.push_back(addr);
2306+
found++;
2307+
}
2308+
addrman.Add(vAdd, resolveSource);
2309+
} else {
2310+
// If the seed does not support a subdomain with our desired service bits,
2311+
// we make an ADDR_FETCH connection to the DNS resolved peer address for the
2312+
// base dns seed domain in chainparams
2313+
AddAddrFetch(seed);
2314+
}
22932315
}
2316+
--seeds_right_now;
22942317
}
2295-
--seeds_right_now;
2318+
LogPrintf("%d addresses found from DNS seeds\n", found);
2319+
} else {
2320+
LogPrintf("Skipping DNS seeds. Enough peers have been found\n");
22962321
}
2297-
LogPrintf("%d addresses found from DNS seeds\n", found);
22982322
}
22992323

23002324
void CConnman::DumpAddresses()
@@ -2345,6 +2369,19 @@ void CConnman::StartExtraBlockRelayPeers()
23452369
m_start_extra_block_relay_peers = true;
23462370
}
23472371

2372+
// Return the number of outbound connections that are full relay (not blocks only)
2373+
int CConnman::GetFullOutboundConnCount() const
2374+
{
2375+
int nRelevant = 0;
2376+
{
2377+
LOCK(m_nodes_mutex);
2378+
for (const CNode* pnode : m_nodes) {
2379+
if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
2380+
}
2381+
}
2382+
return nRelevant;
2383+
}
2384+
23482385
// Return the number of peers we have over our outbound connection limit
23492386
// Exclude peers that are marked for disconnect, or are going to be
23502387
// disconnected soon (eg ADDR_FETCH and FEELER)

src/net.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,8 @@ class CConnman
11731173

11741174
void StartExtraBlockRelayPeers();
11751175

1176+
// Count the number of full-relay peer we have.
1177+
int GetFullOutboundConnCount() const;
11761178
// Return the number of outbound peers we have in excess of our target (eg,
11771179
// if we previously called SetTryNewOutboundPeer(true), and have since set
11781180
// to false, we may have extra peers that we wish to disconnect). This may

0 commit comments

Comments
 (0)