Merge bitcoin/bitcoin#22496: addrman: Remove addrman hotfixes

65332b1178 [addrman] Remove RemoveInvalid() (John Newbery)

Pull request description:

  PRs #22179 and #22112 (EDIT: later reverted in #22497) added hotfix code to addrman to remove invalid addresses and mutate the ports of I2P entries after entering into addrman. Those hotfixes included at least two addrman data corruption bugs:

  - #22467 (Assertion `nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()' failed)
  - #22470 (Changing I2P ports in addrman may wronly skip some entries from "new" buckets)

  Hotfixing addrman is inherently dangerous. There are many members that have implicit assumptions on each others' state, and mutating those directly can lead to violating addrman's internal invariants.

  Instead of trying to hotfix addrman, just don't insert any invalid addresses. For now, those are addresses which fail `CNetAddr::IsValid()`.

ACKs for top commit:
  sipa:
    utACK 65332b1178. I tried to reason through scenarios that could introduce inconsistencies with this code, but can't find any.
  fanquake:
    ACK 65332b1178 - Skipping the addition of invalid addresses (this code was initially added for Tor addrs) rather than adding all the invalids then removing them all when finishing unserializing seems like an improvement. Especially if it can be achieved with less code.

Tree-SHA512: 023113764cb475572f15da7bf9824b62b79e10a7e359af2eee59017df354348d2aeed88de0fd4ad7a9f89a0dad10827f99d70af6f1cb20abb0eca2714689c8d7
pull/22616/head
fanquake 3 years ago
commit 5cf28d5203
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1

@ -77,38 +77,6 @@ double CAddrInfo::GetChance(int64_t nNow) const
return fChance;
}
void CAddrMan::RemoveInvalid()
{
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
for (size_t i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
const auto id = vvNew[bucket][i];
if (id != -1 && !mapInfo[id].IsValid()) {
ClearNew(bucket, i);
}
}
}
for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; ++bucket) {
for (size_t i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
const auto id = vvTried[bucket][i];
if (id == -1) {
continue;
}
const auto& addr_info = mapInfo[id];
if (addr_info.IsValid()) {
continue;
}
vvTried[bucket][i] = -1;
--nTried;
SwapRandom(addr_info.nRandomPos, vRandom.size() - 1);
vRandom.pop_back();
mapAddr.erase(addr_info);
mapInfo.erase(id);
m_tried_collisions.erase(id);
}
}
}
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
{
AssertLockHeld(cs);

@ -365,7 +365,8 @@ public:
s >> info;
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
if (vvTried[nKBucket][nKBucketPos] == -1) {
if (info.IsValid()
&& vvTried[nKBucket][nKBucketPos] == -1) {
info.nRandomPos = vRandom.size();
info.fInTried = true;
vRandom.push_back(nIdCount);
@ -419,6 +420,9 @@ public:
const int entry_index{bucket_entry.second};
CAddrInfo& info = mapInfo[entry_index];
// Don't store the entry in the new bucket if it's not a valid address for our addrman
if (!info.IsValid()) continue;
// The entry shouldn't appear in more than
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
// this bucket_entry.
@ -441,7 +445,7 @@ public:
}
}
// Prune new entries with refcount 0 (as a result of collisions).
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
int nLostUnk = 0;
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
if (it->second.fInTried == false && it->second.nRefCount == 0) {
@ -453,11 +457,9 @@ public:
}
}
if (nLost + nLostUnk > 0) {
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost);
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
}
RemoveInvalid();
Check();
}
@ -772,9 +774,6 @@ private:
//! Update an entry's service bits.
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Remove invalid addresses.
void RemoveInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs);
friend class CAddrManTest;
};

Loading…
Cancel
Save