Skip to content

Commit d35595a

Browse files
committed
addrman: add function to return size by network and table
For now, the new functionality will be used in the context of querying fixed seeds. Other possible applications for future changes is the use in the context of making automatic connections to specific networks, or making more detailed info about addrman accessible via rpc.
1 parent adc41cf commit d35595a

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

src/addrman.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ void AddrManImpl::Unserialize(Stream& s_)
291291
mapAddr[info] = n;
292292
info.nRandomPos = vRandom.size();
293293
vRandom.push_back(n);
294+
m_network_counts[info.GetNetwork()].n_new++;
294295
}
295296
nIdCount = nNew;
296297

@@ -310,6 +311,7 @@ void AddrManImpl::Unserialize(Stream& s_)
310311
mapAddr[info] = nIdCount;
311312
vvTried[nKBucket][nKBucketPos] = nIdCount;
312313
nIdCount++;
314+
m_network_counts[info.GetNetwork()].n_tried++;
313315
} else {
314316
nLost++;
315317
}
@@ -464,6 +466,7 @@ void AddrManImpl::Delete(int nId)
464466
assert(info.nRefCount == 0);
465467

466468
SwapRandom(info.nRandomPos, vRandom.size() - 1);
469+
m_network_counts[info.GetNetwork()].n_new--;
467470
vRandom.pop_back();
468471
mapAddr.erase(info);
469472
mapInfo.erase(nId);
@@ -504,6 +507,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
504507
}
505508
}
506509
nNew--;
510+
m_network_counts[info.GetNetwork()].n_new--;
507511

508512
assert(info.nRefCount == 0);
509513

@@ -522,6 +526,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
522526
infoOld.fInTried = false;
523527
vvTried[nKBucket][nKBucketPos] = -1;
524528
nTried--;
529+
m_network_counts[infoOld.GetNetwork()].n_tried--;
525530

526531
// find which new bucket it belongs to
527532
int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
@@ -533,6 +538,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
533538
infoOld.nRefCount = 1;
534539
vvNew[nUBucket][nUBucketPos] = nIdEvict;
535540
nNew++;
541+
m_network_counts[infoOld.GetNetwork()].n_new++;
536542
LogPrint(BCLog::ADDRMAN, "Moved %s from tried[%i][%i] to new[%i][%i] to make space\n",
537543
infoOld.ToString(), nKBucket, nKBucketPos, nUBucket, nUBucketPos);
538544
}
@@ -541,6 +547,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
541547
vvTried[nKBucket][nKBucketPos] = nId;
542548
nTried++;
543549
info.fInTried = true;
550+
m_network_counts[info.GetNetwork()].n_tried++;
544551
}
545552

546553
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
592599
pinfo = Create(addr, source, &nId);
593600
pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
594601
nNew++;
602+
m_network_counts[pinfo->GetNetwork()].n_new++;
595603
}
596604

597605
int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
@@ -962,6 +970,28 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& ad
962970
}
963971
}
964972

973+
size_t AddrManImpl::Size_(std::optional<Network> net, std::optional<bool> in_new) const
974+
{
975+
AssertLockHeld(cs);
976+
977+
if (!net.has_value()) {
978+
if (in_new.has_value()) {
979+
return *in_new ? nNew : nTried;
980+
} else {
981+
return vRandom.size();
982+
}
983+
}
984+
if (auto it = m_network_counts.find(*net); it != m_network_counts.end()) {
985+
auto net_count = it->second;
986+
if (in_new.has_value()) {
987+
return *in_new ? net_count.n_new : net_count.n_tried;
988+
} else {
989+
return net_count.n_new + net_count.n_tried;
990+
}
991+
}
992+
return 0;
993+
}
994+
965995
void AddrManImpl::Check() const
966996
{
967997
AssertLockHeld(cs);
@@ -986,6 +1016,7 @@ int AddrManImpl::CheckAddrman() const
9861016

9871017
std::unordered_set<int> setTried;
9881018
std::unordered_map<int, int> mapNew;
1019+
std::unordered_map<Network, NewTriedCount> local_counts;
9891020

9901021
if (vRandom.size() != (size_t)(nTried + nNew))
9911022
return -7;
@@ -1000,12 +1031,14 @@ int AddrManImpl::CheckAddrman() const
10001031
if (info.nRefCount)
10011032
return -2;
10021033
setTried.insert(n);
1034+
local_counts[info.GetNetwork()].n_tried++;
10031035
} else {
10041036
if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
10051037
return -3;
10061038
if (!info.nRefCount)
10071039
return -4;
10081040
mapNew[n] = info.nRefCount;
1041+
local_counts[info.GetNetwork()].n_new++;
10091042
}
10101043
const auto it{mapAddr.find(info)};
10111044
if (it == mapAddr.end() || it->second != n) {
@@ -1065,6 +1098,17 @@ int AddrManImpl::CheckAddrman() const
10651098
if (nKey.IsNull())
10661099
return -16;
10671100

1101+
// It's possible that m_network_counts may have all-zero entries that local_counts
1102+
// doesn't have if addrs from a network were being added and then removed again in the past.
1103+
if (m_network_counts.size() < local_counts.size()) {
1104+
return -20;
1105+
}
1106+
for (const auto& [net, count] : m_network_counts) {
1107+
if (local_counts[net].n_new != count.n_new || local_counts[net].n_tried != count.n_tried) {
1108+
return -21;
1109+
}
1110+
}
1111+
10681112
return 0;
10691113
}
10701114

@@ -1074,6 +1118,15 @@ size_t AddrManImpl::size() const
10741118
return vRandom.size();
10751119
}
10761120

1121+
size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new) const
1122+
{
1123+
LOCK(cs);
1124+
Check();
1125+
auto ret = Size_(net, in_new);
1126+
Check();
1127+
return ret;
1128+
}
1129+
10771130
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
10781131
{
10791132
LOCK(cs);
@@ -1191,6 +1244,11 @@ size_t AddrMan::size() const
11911244
return m_impl->size();
11921245
}
11931246

1247+
size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) const
1248+
{
1249+
return m_impl->Size(net, in_new);
1250+
}
1251+
11941252
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
11951253
{
11961254
return m_impl->Add(vAddr, source, time_penalty);

src/addrman.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ class AddrMan
102102
//! Return the number of (unique) addresses in all tables.
103103
size_t size() const;
104104

105+
/**
106+
* Return size information about addrman.
107+
*
108+
* @param[in] net Select addresses only from specified network (nullopt = all)
109+
* @param[in] in_new Select addresses only from one table (true = new, false = tried, nullopt = both)
110+
* @return Number of unique addresses that match specified options.
111+
*/
112+
size_t Size(std::optional<Network> net, std::optional<bool> in_new) const;
113+
105114
/**
106115
* Attempt to add one or more addresses to addrman's new table.
107116
*

src/addrman_impl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class AddrManImpl
114114

115115
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
116116

117+
size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
118+
117119
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
118120
EXCLUSIVE_LOCKS_REQUIRED(!cs);
119121

@@ -215,6 +217,14 @@ class AddrManImpl
215217
/** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */
216218
const NetGroupManager& m_netgroupman;
217219

220+
struct NewTriedCount {
221+
size_t n_new;
222+
size_t n_tried;
223+
};
224+
225+
/** Number of entries in addrman per network and new/tried table. */
226+
std::unordered_map<Network, NewTriedCount> m_network_counts GUARDED_BY(cs);
227+
218228
//! Find an entry.
219229
AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
220230

@@ -257,6 +267,8 @@ class AddrManImpl
257267

258268
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
259269

270+
size_t Size_(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(cs);
271+
260272
//! Consistency check, taking into account m_consistency_check_ratio.
261273
//! Will std::abort if an inconsistency is detected.
262274
void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs);

src/test/addrman_tests.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,4 +990,42 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
990990
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
991991
}
992992

993+
BOOST_AUTO_TEST_CASE(addrman_size)
994+
{
995+
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
996+
const CNetAddr source = ResolveIP("252.2.2.2");
997+
998+
// empty addrman
999+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 0U);
1000+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 0U);
1001+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 0U);
1002+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 0U);
1003+
1004+
// add two ipv4 addresses, one to tried and new
1005+
const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
1006+
BOOST_CHECK(addrman->Add({addr1}, source));
1007+
BOOST_CHECK(addrman->Good(addr1));
1008+
const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
1009+
BOOST_CHECK(addrman->Add({addr2}, source));
1010+
1011+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 2U);
1012+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1013+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 1U);
1014+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1015+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/true), 1U);
1016+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 1U);
1017+
1018+
// add one i2p address to new
1019+
CService i2p_addr;
1020+
i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
1021+
const CAddress addr3{i2p_addr, NODE_NONE};
1022+
BOOST_CHECK(addrman->Add({addr3}, source));
1023+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 3U);
1024+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1025+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/std::nullopt), 1U);
1026+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/true), 1U);
1027+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 2U);
1028+
BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1029+
}
1030+
9931031
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)