aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/addrman.cpp58
-rw-r--r--src/addrman.h9
-rw-r--r--src/addrman_impl.h12
-rw-r--r--src/test/addrman_tests.cpp38
4 files changed, 117 insertions, 0 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 9e859c4d67..89da34c419 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -291,6 +291,7 @@ void AddrManImpl::Unserialize(Stream& s_)
mapAddr[info] = n;
info.nRandomPos = vRandom.size();
vRandom.push_back(n);
+ m_network_counts[info.GetNetwork()].n_new++;
}
nIdCount = nNew;
@@ -310,6 +311,7 @@ void AddrManImpl::Unserialize(Stream& s_)
mapAddr[info] = nIdCount;
vvTried[nKBucket][nKBucketPos] = nIdCount;
nIdCount++;
+ m_network_counts[info.GetNetwork()].n_tried++;
} else {
nLost++;
}
@@ -464,6 +466,7 @@ void AddrManImpl::Delete(int nId)
assert(info.nRefCount == 0);
SwapRandom(info.nRandomPos, vRandom.size() - 1);
+ m_network_counts[info.GetNetwork()].n_new--;
vRandom.pop_back();
mapAddr.erase(info);
mapInfo.erase(nId);
@@ -504,6 +507,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
}
}
nNew--;
+ m_network_counts[info.GetNetwork()].n_new--;
assert(info.nRefCount == 0);
@@ -522,6 +526,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
infoOld.fInTried = false;
vvTried[nKBucket][nKBucketPos] = -1;
nTried--;
+ m_network_counts[infoOld.GetNetwork()].n_tried--;
// find which new bucket it belongs to
int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
@@ -533,6 +538,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
infoOld.nRefCount = 1;
vvNew[nUBucket][nUBucketPos] = nIdEvict;
nNew++;
+ m_network_counts[infoOld.GetNetwork()].n_new++;
LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
}
@@ -541,6 +547,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
vvTried[nKBucket][nKBucketPos] = nId;
nTried++;
info.fInTried = true;
+ m_network_counts[info.GetNetwork()].n_tried++;
}
bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
@@ -592,6 +599,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::c
pinfo = Create(addr, source, &nId);
pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
nNew++;
+ m_network_counts[pinfo->GetNetwork()].n_new++;
}
int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
@@ -962,6 +970,28 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& ad
}
}
+size_t AddrManImpl::Size_(std::optional<Network> net, std::optional<bool> in_new) const
+{
+ AssertLockHeld(cs);
+
+ if (!net.has_value()) {
+ if (in_new.has_value()) {
+ return *in_new ? nNew : nTried;
+ } else {
+ return vRandom.size();
+ }
+ }
+ if (auto it = m_network_counts.find(*net); it != m_network_counts.end()) {
+ auto net_count = it->second;
+ if (in_new.has_value()) {
+ return *in_new ? net_count.n_new : net_count.n_tried;
+ } else {
+ return net_count.n_new + net_count.n_tried;
+ }
+ }
+ return 0;
+}
+
void AddrManImpl::Check() const
{
AssertLockHeld(cs);
@@ -986,6 +1016,7 @@ int AddrManImpl::CheckAddrman() const
std::unordered_set<int> setTried;
std::unordered_map<int, int> mapNew;
+ std::unordered_map<Network, NewTriedCount> local_counts;
if (vRandom.size() != (size_t)(nTried + nNew))
return -7;
@@ -1000,12 +1031,14 @@ int AddrManImpl::CheckAddrman() const
if (info.nRefCount)
return -2;
setTried.insert(n);
+ local_counts[info.GetNetwork()].n_tried++;
} else {
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
return -3;
if (!info.nRefCount)
return -4;
mapNew[n] = info.nRefCount;
+ local_counts[info.GetNetwork()].n_new++;
}
const auto it{mapAddr.find(info)};
if (it == mapAddr.end() || it->second != n) {
@@ -1065,6 +1098,17 @@ int AddrManImpl::CheckAddrman() const
if (nKey.IsNull())
return -16;
+ // It's possible that m_network_counts may have all-zero entries that local_counts
+ // doesn't have if addrs from a network were being added and then removed again in the past.
+ if (m_network_counts.size() < local_counts.size()) {
+ return -20;
+ }
+ for (const auto& [net, count] : m_network_counts) {
+ if (local_counts[net].n_new != count.n_new || local_counts[net].n_tried != count.n_tried) {
+ return -21;
+ }
+ }
+
return 0;
}
@@ -1074,6 +1118,15 @@ size_t AddrManImpl::size() const
return vRandom.size();
}
+size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new) const
+{
+ LOCK(cs);
+ Check();
+ auto ret = Size_(net, in_new);
+ Check();
+ return ret;
+}
+
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
LOCK(cs);
@@ -1191,6 +1244,11 @@ size_t AddrMan::size() const
return m_impl->size();
}
+size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const
+{
+ return m_impl->Size(net, in_new);
+}
+
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
return m_impl->Add(vAddr, source, time_penalty);
diff --git a/src/addrman.h b/src/addrman.h
index 0f1f808fa1..1c7254b5d7 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -103,6 +103,15 @@ public:
size_t size() const;
/**
+ * Return size information about addrman.
+ *
+ * @param[in] net Select addresses only from specified network (nullopt = all)
+ * @param[in] in_new Select addresses only from one table (true = new, false = tried, nullopt = both)
+ * @return Number of unique addresses that match specified options.
+ */
+ size_t Size(std::optional<Network> net, std::optional<bool> in_new) const;
+
+ /**
* Attempt to add one or more addresses to addrman's new table.
*
* @param[in] vAddr Address records to attempt to add.
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 39754b673e..f75cccb303 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -114,6 +114,8 @@ public:
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
+ size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
+
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
@@ -215,6 +217,14 @@ private:
/** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */
const NetGroupManager& m_netgroupman;
+ struct NewTriedCount {
+ size_t n_new;
+ size_t n_tried;
+ };
+
+ /** Number of entries in addrman per network and new/tried table. */
+ std::unordered_map<Network, NewTriedCount> m_network_counts GUARDED_BY(cs);
+
//! Find an entry.
AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
@@ -257,6 +267,8 @@ private:
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ size_t Size_(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
//! Consistency check, taking into account m_consistency_check_ratio.
//! Will std::abort if an inconsistency is detected.
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index b15df43e8c..da12441fe8 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -990,4 +990,42 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
}
+BOOST_AUTO_TEST_CASE(addrman_size)
+{
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
+ const CNetAddr source = ResolveIP("252.2.2.2");
+
+ // empty addrman
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 0U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 0U);
+
+ // add two ipv4 addresses, one to tried and new
+ const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr1}, source));
+ BOOST_CHECK(addrman->Good(addr1));
+ const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr2}, source));
+
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 1U);
+
+ // add one i2p address to new
+ CService i2p_addr;
+ i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
+ const CAddress addr3{i2p_addr, NODE_NONE};
+ BOOST_CHECK(addrman->Add({addr3}, source));
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 3U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/std::nullopt), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/true), 1U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 2U);
+ BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
+}
+
BOOST_AUTO_TEST_SUITE_END()