diff --git a/src/addrman.h b/src/addrman.h --- a/src/addrman.h +++ b/src/addrman.h @@ -180,6 +180,10 @@ //! the maximum number of tried addr collisions to store #define ADDRMAN_SET_TRIED_COLLISION_SIZE 10 +//! the maximum time we'll spend trying to resolve a tried table collision, in +//! seconds (40 minutes) +static const int64_t ADDRMAN_TEST_WINDOW = 40 * 60; + /** * Stochastical (IP) address manager */ diff --git a/src/addrman.cpp b/src/addrman.cpp --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -266,9 +266,15 @@ // Will moving this address into tried evict another entry? if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) { + // Output the entry we'd be colliding with, for debugging purposes + auto colliding_entry = + mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]); LogPrint(BCLog::ADDRMAN, - "Collision inserting element into tried table, moving %s to " - "m_tried_collisions=%d\n", + "Collision inserting element into tried table (%s), moving %s " + "to m_tried_collisions=%d\n", + colliding_entry != mapInfo.end() + ? colliding_entry->second.ToString() + : "", addr.ToString(), m_tried_collisions.size()); if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) { m_tried_collisions.insert(nId); @@ -658,14 +664,25 @@ // Give address at least 60 seconds to successfully connect if (GetAdjustedTime() - info_old.nLastTry > 60) { LogPrint(BCLog::ADDRMAN, - "Swapping %s for %s in tried table\n", - info_new.ToString(), info_old.ToString()); + "Replacing %s with %s in tried table\n", + info_old.ToString(), info_new.ToString()); // Replaces an existing address already in the tried // table with the new address Good_(info_new, false, GetAdjustedTime()); erase_collision = true; } + } else if (GetAdjustedTime() - info_new.nLastSuccess > + ADDRMAN_TEST_WINDOW) { + // If the collision hasn't resolved in some reasonable + // amount of time, just evict the old entry -- we must not + // be able to connect to it for some reason. + LogPrint(BCLog::ADDRMAN, + "Unable to test; replacing %s with %s in tried " + "table anyway\n", + info_old.ToString(), info_new.ToString()); + Good_(info_new, false, GetAdjustedTime()); + erase_collision = true; } } else { // Collision is not actually a collision anymore diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -1931,9 +1931,14 @@ addr = addrman.Select(fFeeler); } - // if we selected an invalid address, restart - if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || - IsLocal(addr)) { + // Require outbound connections, other than feelers, to be to + // distinct network groups + if (!fFeeler && setConnected.count(addr.GetGroup())) { + break; + } + + // if we selected an invalid or local address, restart + if (!addr.IsValid() || IsLocal(addr)) { break; }