Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
addrman_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2012-2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <addrdb.h>
6#include <addrman.h>
7#include <addrman_impl.h>
8#include <chainparams.h>
9#include <clientversion.h>
10#include <hash.h>
11#include <netbase.h>
12#include <random.h>
13#include <test/data/asmap.raw.h>
15#include <util/asmap.h>
16#include <util/string.h>
17
18#include <boost/test/unit_test.hpp>
19
20#include <optional>
21#include <string>
22
23using namespace std::literals;
25using util::ToString;
26
27static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
28static const bool DETERMINISTIC{true};
29
30static int32_t GetCheckRatio(const NodeContext& node_ctx)
31{
32 return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
33}
34
35static CNetAddr ResolveIP(const std::string& ip)
36{
37 const std::optional<CNetAddr> addr{LookupHost(ip, false)};
38 BOOST_CHECK_MESSAGE(addr.has_value(), strprintf("failed to resolve: %s", ip));
39 return addr.value_or(CNetAddr{});
40}
41
42static CService ResolveService(const std::string& ip, uint16_t port = 0)
43{
44 const std::optional<CService> serv{Lookup(ip, port, false)};
45 BOOST_CHECK_MESSAGE(serv.has_value(), strprintf("failed to resolve: %s:%i", ip, port));
46 return serv.value_or(CService{});
47}
48
49
50static std::vector<bool> FromBytes(const unsigned char* source, int vector_size)
51{
52 std::vector<bool> result(vector_size);
53 for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) {
54 unsigned char cur_byte = source[byte_i];
55 for (int bit_i = 0; bit_i < 8; ++bit_i) {
56 result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1;
57 }
58 }
59 return result;
60}
61
62BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
63
64BOOST_AUTO_TEST_CASE(addrman_simple)
65{
66 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
67
68 CNetAddr source = ResolveIP("252.2.2.2");
69
70 // Test: Does Addrman respond correctly when empty.
71 BOOST_CHECK_EQUAL(addrman->Size(), 0U);
72 auto addr_null = addrman->Select().first;
73 BOOST_CHECK_EQUAL(addr_null.ToStringAddrPort(), "[::]:0");
74
75 // Test: Does Addrman::Add work as expected.
76 CService addr1 = ResolveService("250.1.1.1", 8333);
77 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
78 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
79 auto addr_ret1 = addrman->Select().first;
80 BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
81
82 // Test: Does IP address deduplication work correctly.
83 // Expected dup IP should not be added.
84 CService addr1_dup = ResolveService("250.1.1.1", 8333);
85 BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
86 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
87
88
89 // Test: New table has one addr and we add a diff addr we should
90 // have at least one addr.
91 // Note that addrman's size cannot be tested reliably after insertion, as
92 // hash collisions may occur. But we can always be sure of at least one
93 // success.
94
95 CService addr2 = ResolveService("250.1.1.2", 8333);
96 BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
97 BOOST_CHECK(addrman->Size() >= 1);
98
99 // Test: reset addrman and test AddrMan::Add multiple addresses works as expected
100 addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
101 std::vector<CAddress> vAddr;
102 vAddr.emplace_back(ResolveService("250.1.1.3", 8333), NODE_NONE);
103 vAddr.emplace_back(ResolveService("250.1.1.4", 8333), NODE_NONE);
104 BOOST_CHECK(addrman->Add(vAddr, source));
105 BOOST_CHECK(addrman->Size() >= 1);
106}
107
109{
110 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
111
112 CNetAddr source = ResolveIP("252.2.2.2");
113
114 BOOST_CHECK_EQUAL(addrman->Size(), 0U);
115
116 // Test 7; Addr with same IP but diff port does not replace existing addr.
117 CService addr1 = ResolveService("250.1.1.1", 8333);
118 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
119 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
120
121 CService addr1_port = ResolveService("250.1.1.1", 8334);
122 BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));
123 BOOST_CHECK_EQUAL(addrman->Size(), 2U);
124 auto addr_ret2 = addrman->Select().first;
125 BOOST_CHECK(addr_ret2.ToStringAddrPort() == "250.1.1.1:8333" || addr_ret2.ToStringAddrPort() == "250.1.1.1:8334");
126
127 // Test: Add same IP but diff port to tried table; this converts the entry with
128 // the specified port to tried, but not the other.
129 addrman->Good(CAddress(addr1_port, NODE_NONE));
130 BOOST_CHECK_EQUAL(addrman->Size(), 2U);
131 bool new_only = true;
132 auto addr_ret3 = addrman->Select(new_only).first;
133 BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
134}
135
136BOOST_AUTO_TEST_CASE(addrman_select)
137{
138 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
139 BOOST_CHECK(!addrman->Select(false).first.IsValid());
140 BOOST_CHECK(!addrman->Select(true).first.IsValid());
141
142 CNetAddr source = ResolveIP("252.2.2.2");
143
144 // Add 1 address to the new table
145 CService addr1 = ResolveService("250.1.1.1", 8333);
146 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
147 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
148
149 BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr1);
150 BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
151
152 // Move address to the tried table
153 BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
154
155 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
156 BOOST_CHECK(!addrman->Select(/*new_only=*/true).first.IsValid());
157 BOOST_CHECK(addrman->Select().first == addr1);
158 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
159
160 // Add one address to the new table
161 CService addr2 = ResolveService("250.3.1.1", 8333);
162 BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, addr2));
163 BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr2);
164
165 // Add two more addresses to the new table
166 CService addr3 = ResolveService("250.3.2.2", 9999);
167 CService addr4 = ResolveService("250.3.3.3", 9999);
168
169 BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, addr2));
170 BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));
171
172 // Add three addresses to tried table.
173 CService addr5 = ResolveService("250.4.4.4", 8333);
174 CService addr6 = ResolveService("250.4.5.5", 7777);
175 CService addr7 = ResolveService("250.4.6.6", 8333);
176
177 BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, addr3));
178 BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));
179 BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, addr3));
180 BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE)));
181 BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));
182 BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));
183
184 // 6 addrs + 1 addr from last test = 7.
185 BOOST_CHECK_EQUAL(addrman->Size(), 7U);
186
187 // Select pulls from new and tried regardless of port number.
188 std::set<uint16_t> ports;
189 for (int i = 0; i < 20; ++i) {
190 ports.insert(addrman->Select().first.GetPort());
191 }
192 BOOST_CHECK_EQUAL(ports.size(), 3U);
193}
194
195BOOST_AUTO_TEST_CASE(addrman_select_by_network)
196{
197 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
198 BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_IPV4).first.IsValid());
199 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV4).first.IsValid());
200
201 // add ipv4 address to the new table
202 CNetAddr source = ResolveIP("252.2.2.2");
203 CService addr1 = ResolveService("250.1.1.1", 8333);
204 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
205
206 BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_IPV4).first == addr1);
207 BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
208 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid());
209 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid());
210 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_I2P).first.IsValid());
211 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid());
212 BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_CJDNS).first.IsValid());
213 BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
214
215 // add I2P address to the new table
216 CAddress i2p_addr;
217 i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
218 BOOST_CHECK(addrman->Add({i2p_addr}, source));
219
220 BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr);
221 BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr);
222 BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
223 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid());
224 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid());
225 BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid());
226
227 // bump I2P address to tried table
228 BOOST_CHECK(addrman->Good(i2p_addr));
229
230 BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_I2P).first.IsValid());
231 BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr);
232
233 // add another I2P address to the new table
234 CAddress i2p_addr2;
235 i2p_addr2.SetSpecial("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p");
236 BOOST_CHECK(addrman->Add({i2p_addr2}, source));
237
238 BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr2);
239
240 // ensure that both new and tried table are selected from
241 bool new_selected{false};
242 bool tried_selected{false};
243 int counter = 256;
244
245 while (--counter > 0 && (!new_selected || !tried_selected)) {
246 const CAddress selected{addrman->Select(/*new_only=*/false, NET_I2P).first};
247 BOOST_REQUIRE(selected == i2p_addr || selected == i2p_addr2);
248 if (selected == i2p_addr) {
249 tried_selected = true;
250 } else {
251 new_selected = true;
252 }
253 }
254
255 BOOST_CHECK(new_selected);
256 BOOST_CHECK(tried_selected);
257}
258
259BOOST_AUTO_TEST_CASE(addrman_select_special)
260{
261 // use a non-deterministic addrman to ensure a passing test isn't due to setup
262 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, /*deterministic=*/false, GetCheckRatio(m_node));
263
264 CNetAddr source = ResolveIP("252.2.2.2");
265
266 // add I2P address to the tried table
267 CAddress i2p_addr;
268 i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
269 BOOST_CHECK(addrman->Add({i2p_addr}, source));
270 BOOST_CHECK(addrman->Good(i2p_addr));
271
272 // add ipv4 address to the new table
273 CService addr1 = ResolveService("250.1.1.3", 8333);
274 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
275
276 // since the only ipv4 address is on the new table, ensure that the new
277 // table gets selected even if new_only is false. if the table was being
278 // selected at random, this test will sporadically fail
279 BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
280}
281
282BOOST_AUTO_TEST_CASE(addrman_new_collisions)
283{
284 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
285
286 CNetAddr source = ResolveIP("252.2.2.2");
287
288 uint32_t num_addrs{0};
289
290 BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
291
292 while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
293 CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
294 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
295
296 // Test: No collision in new table yet.
297 BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
298 }
299
300 // Test: new table collision!
301 CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
302 uint32_t collisions{1};
303 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
304 BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
305
306 CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
307 BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
308 BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
309}
310
311BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
312{
313 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
314 CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
315 const auto start_time{Now<NodeSeconds>()};
316 addr.nTime = start_time;
317
318 // test that multiplicity stays at 1 if nTime doesn't increase
319 for (unsigned int i = 1; i < 20; ++i) {
320 std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
321 CNetAddr source{ResolveIP(addr_ip)};
322 addrman->Add({addr}, source);
323 }
324 AddressPosition addr_pos = addrman->FindAddressEntry(addr).value();
325 BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U);
326 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
327
328 // if nTime increases, an addr can occur in up to 8 buckets
329 // The acceptance probability decreases exponentially with existing multiplicity -
330 // choose number of iterations such that it gets to 8 with deterministic addrman.
331 for (unsigned int i = 1; i < 400; ++i) {
332 std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
333 CNetAddr source{ResolveIP(addr_ip)};
334 addr.nTime = start_time + std::chrono::seconds{i};
335 addrman->Add({addr}, source);
336 }
337 AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
338 BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U);
339 // multiplicity doesn't affect size
340 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
341}
342
343BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
344{
345 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
346
347 CNetAddr source = ResolveIP("252.2.2.2");
348
349 uint32_t num_addrs{0};
350
351 BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
352
353 while (num_addrs < 35) { // Magic number! 250.1.1.1 - 250.1.1.35 do not collide in tried with deterministic key = 1
354 CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
355 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
356
357 // Test: Add to tried without collision
358 BOOST_CHECK(addrman->Good(CAddress(addr, NODE_NONE)));
359
360 }
361
362 // Test: Unable to add to tried table due to collision!
363 CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
364 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
365 BOOST_CHECK(!addrman->Good(CAddress(addr1, NODE_NONE)));
366
367 // Test: Add the next address to tried without collision
368 CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
369 BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
370 BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
371}
372
373
374BOOST_AUTO_TEST_CASE(addrman_getaddr)
375{
376 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
377
378 // Test: Sanity check, GetAddr should never return anything if addrman
379 // is empty.
380 BOOST_CHECK_EQUAL(addrman->Size(), 0U);
381 std::vector<CAddress> vAddr1 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
382 BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
383
384 CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
385 addr1.nTime = Now<NodeSeconds>(); // Set time so isTerrible = false
386 CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
387 addr2.nTime = Now<NodeSeconds>();
388 CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
389 addr3.nTime = Now<NodeSeconds>();
390 CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
391 addr4.nTime = Now<NodeSeconds>();
392 CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
393 addr5.nTime = Now<NodeSeconds>();
394 CNetAddr source1 = ResolveIP("250.1.2.1");
395 CNetAddr source2 = ResolveIP("250.2.3.3");
396
397 // Test: Ensure GetAddr works with new addresses.
398 BOOST_CHECK(addrman->Add({addr1, addr3, addr5}, source1));
399 BOOST_CHECK(addrman->Add({addr2, addr4}, source2));
400
401 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
402 // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
403 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
404
405 // Test: Ensure GetAddr works with new and tried addresses.
406 BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
407 BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
408 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
409 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
410
411 // Test: Ensure GetAddr still returns 23% when addrman has many addrs.
412 for (unsigned int i = 1; i < (8 * 256); i++) {
413 int octet1 = i % 256;
414 int octet2 = i >> 8 % 256;
415 std::string strAddr = ToString(octet1) + "." + ToString(octet2) + ".1.23";
416 CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
417
418 // Ensure that for all addrs in addrman, isTerrible == false.
419 addr.nTime = Now<NodeSeconds>();
420 addrman->Add({addr}, ResolveIP(strAddr));
421 if (i % 8 == 0)
422 addrman->Good(addr);
423 }
424 std::vector<CAddress> vAddr = addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
425
426 size_t percent23 = (addrman->Size() * 23) / 100;
427 BOOST_CHECK_EQUAL(vAddr.size(), percent23);
428 BOOST_CHECK_EQUAL(vAddr.size(), 461U);
429 // (addrman.Size() < number of addresses added) due to address collisions.
430 BOOST_CHECK_EQUAL(addrman->Size(), 2006U);
431}
432
433BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
434{
435 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
436
437 // Set time on this addr so isTerrible = false
438 CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
439 addr1.nTime = Now<NodeSeconds>();
440 // Not setting time so this addr should be isTerrible = true
441 CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
442
443 CNetAddr source = ResolveIP("250.1.2.1");
444 BOOST_CHECK(addrman->Add({addr1, addr2}, source));
445
446 // Filtered GetAddr should only return addr1
447 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
448 // Unfiltered GetAddr should return addr1 and addr2
449 BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 2U);
450}
451
452BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
453{
454 CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
455 CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
456
457 CNetAddr source1 = ResolveIP("250.1.1.1");
458
459
460 AddrInfo info1 = AddrInfo(addr1, source1);
461
462 uint256 nKey1 = (HashWriter{} << 1).GetHash();
463 uint256 nKey2 = (HashWriter{} << 2).GetHash();
464
466
467 // Test: Make sure key actually randomizes bucket placement. A fail on
468 // this test could be a security issue.
470
471 // Test: Two addresses with same IP but different ports can map to
472 // different buckets because they have different keys.
473 AddrInfo info2 = AddrInfo(addr2, source1);
474
475 BOOST_CHECK(info1.GetKey() != info2.GetKey());
477
478 std::set<int> buckets;
479 for (int i = 0; i < 255; i++) {
480 AddrInfo infoi = AddrInfo(
481 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
482 ResolveIP("250.1.1." + ToString(i)));
483 int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
484 buckets.insert(bucket);
485 }
486 // Test: IP addresses in the same /16 prefix should
487 // never get more than 8 buckets with legacy grouping
488 BOOST_CHECK_EQUAL(buckets.size(), 8U);
489
490 buckets.clear();
491 for (int j = 0; j < 255; j++) {
492 AddrInfo infoj = AddrInfo(
493 CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
494 ResolveIP("250." + ToString(j) + ".1.1"));
495 int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
496 buckets.insert(bucket);
497 }
498 // Test: IP addresses in the different /16 prefix should map to more than
499 // 8 buckets with legacy grouping
500 BOOST_CHECK_EQUAL(buckets.size(), 160U);
501}
502
503BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
504{
505 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
506 CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
507
508 CNetAddr source1 = ResolveIP("250.1.2.1");
509
510 AddrInfo info1 = AddrInfo(addr1, source1);
511
512 uint256 nKey1 = (HashWriter{} << 1).GetHash();
513 uint256 nKey2 = (HashWriter{} << 2).GetHash();
514
515 // Test: Make sure the buckets are what we expect
517 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);
518
519 // Test: Make sure key actually randomizes bucket placement. A fail on
520 // this test could be a security issue.
522
523 // Test: Ports should not affect bucket placement in the addr
524 AddrInfo info2 = AddrInfo(addr2, source1);
525 BOOST_CHECK(info1.GetKey() != info2.GetKey());
527
528 std::set<int> buckets;
529 for (int i = 0; i < 255; i++) {
530 AddrInfo infoi = AddrInfo(
531 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
532 ResolveIP("250.1.1." + ToString(i)));
533 int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
534 buckets.insert(bucket);
535 }
536 // Test: IP addresses in the same group (\16 prefix for IPv4) should
537 // always map to the same bucket.
538 BOOST_CHECK_EQUAL(buckets.size(), 1U);
539
540 buckets.clear();
541 for (int j = 0; j < 4 * 255; j++) {
542 AddrInfo infoj = AddrInfo(CAddress(
544 ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
545 ResolveIP("251.4.1.1"));
546 int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
547 buckets.insert(bucket);
548 }
549 // Test: IP addresses in the same source groups should map to NO MORE
550 // than 64 buckets.
551 BOOST_CHECK(buckets.size() <= 64);
552
553 buckets.clear();
554 for (int p = 0; p < 255; p++) {
555 AddrInfo infoj = AddrInfo(
556 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
557 ResolveIP("250." + ToString(p) + ".1.1"));
558 int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
559 buckets.insert(bucket);
560 }
561 // Test: IP addresses in the different source groups should map to MORE
562 // than 64 buckets.
563 BOOST_CHECK(buckets.size() > 64);
564}
565
566// The following three test cases use asmap.raw
567// We use an artificial minimal mock mapping
568// 250.0.0.0/8 AS1000
569// 101.1.0.0/16 AS1
570// 101.2.0.0/16 AS2
571// 101.3.0.0/16 AS3
572// 101.4.0.0/16 AS4
573// 101.5.0.0/16 AS5
574// 101.6.0.0/16 AS6
575// 101.7.0.0/16 AS7
576// 101.8.0.0/16 AS8
577BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
578{
579 std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
580 NetGroupManager ngm_asmap{asmap};
581
582 CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
583 CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
584
585 CNetAddr source1 = ResolveIP("250.1.1.1");
586
587
588 AddrInfo info1 = AddrInfo(addr1, source1);
589
590 uint256 nKey1 = (HashWriter{} << 1).GetHash();
591 uint256 nKey2 = (HashWriter{} << 2).GetHash();
592
593 BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);
594
595 // Test: Make sure key actually randomizes bucket placement. A fail on
596 // this test could be a security issue.
597 BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));
598
599 // Test: Two addresses with same IP but different ports can map to
600 // different buckets because they have different keys.
601 AddrInfo info2 = AddrInfo(addr2, source1);
602
603 BOOST_CHECK(info1.GetKey() != info2.GetKey());
604 BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));
605
606 std::set<int> buckets;
607 for (int j = 0; j < 255; j++) {
608 AddrInfo infoj = AddrInfo(
609 CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
610 ResolveIP("101." + ToString(j) + ".1.1"));
611 int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
612 buckets.insert(bucket);
613 }
614 // Test: IP addresses in the different /16 prefix MAY map to more than
615 // 8 buckets.
616 BOOST_CHECK(buckets.size() > 8);
617
618 buckets.clear();
619 for (int j = 0; j < 255; j++) {
620 AddrInfo infoj = AddrInfo(
621 CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
622 ResolveIP("250." + ToString(j) + ".1.1"));
623 int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
624 buckets.insert(bucket);
625 }
626 // Test: IP addresses in the different /16 prefix MAY NOT map to more than
627 // 8 buckets.
628 BOOST_CHECK(buckets.size() == 8);
629}
630
631BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
632{
633 std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
634 NetGroupManager ngm_asmap{asmap};
635
636 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
637 CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
638
639 CNetAddr source1 = ResolveIP("250.1.2.1");
640
641 AddrInfo info1 = AddrInfo(addr1, source1);
642
643 uint256 nKey1 = (HashWriter{} << 1).GetHash();
644 uint256 nKey2 = (HashWriter{} << 2).GetHash();
645
646 // Test: Make sure the buckets are what we expect
647 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);
648 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);
649
650 // Test: Make sure key actually randomizes bucket placement. A fail on
651 // this test could be a security issue.
652 BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));
653
654 // Test: Ports should not affect bucket placement in the addr
655 AddrInfo info2 = AddrInfo(addr2, source1);
656 BOOST_CHECK(info1.GetKey() != info2.GetKey());
657 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));
658
659 std::set<int> buckets;
660 for (int i = 0; i < 255; i++) {
661 AddrInfo infoi = AddrInfo(
662 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
663 ResolveIP("250.1.1." + ToString(i)));
664 int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);
665 buckets.insert(bucket);
666 }
667 // Test: IP addresses in the same /16 prefix
668 // usually map to the same bucket.
669 BOOST_CHECK_EQUAL(buckets.size(), 1U);
670
671 buckets.clear();
672 for (int j = 0; j < 4 * 255; j++) {
673 AddrInfo infoj = AddrInfo(CAddress(
675 ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
676 ResolveIP("251.4.1.1"));
677 int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
678 buckets.insert(bucket);
679 }
680 // Test: IP addresses in the same source /16 prefix should not map to more
681 // than 64 buckets.
682 BOOST_CHECK(buckets.size() <= 64);
683
684 buckets.clear();
685 for (int p = 0; p < 255; p++) {
686 AddrInfo infoj = AddrInfo(
687 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
688 ResolveIP("101." + ToString(p) + ".1.1"));
689 int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
690 buckets.insert(bucket);
691 }
692 // Test: IP addresses in the different source /16 prefixes usually map to MORE
693 // than 1 bucket.
694 BOOST_CHECK(buckets.size() > 1);
695
696 buckets.clear();
697 for (int p = 0; p < 255; p++) {
698 AddrInfo infoj = AddrInfo(
699 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
700 ResolveIP("250." + ToString(p) + ".1.1"));
701 int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
702 buckets.insert(bucket);
703 }
704 // Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
705 // than 1 bucket.
706 BOOST_CHECK(buckets.size() == 1);
707}
708
709BOOST_AUTO_TEST_CASE(addrman_serialization)
710{
711 std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
712 NetGroupManager netgroupman{asmap1};
713
714 const auto ratio = GetCheckRatio(m_node);
715 auto addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
716 auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
717 auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
718
719 DataStream stream{};
720
721 CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
722 CNetAddr default_source;
723
724 addrman_asmap1->Add({addr}, default_source);
725
726 stream << *addrman_asmap1;
727 // serizalizing/deserializing addrman with the same asmap
728 stream >> *addrman_asmap1_dup;
729
730 AddressPosition addr_pos1 = addrman_asmap1->FindAddressEntry(addr).value();
731 AddressPosition addr_pos2 = addrman_asmap1_dup->FindAddressEntry(addr).value();
732 BOOST_CHECK(addr_pos1.multiplicity != 0);
733 BOOST_CHECK(addr_pos2.multiplicity != 0);
734
735 BOOST_CHECK(addr_pos1 == addr_pos2);
736
737 // deserializing asmaped peers.dat to non-asmaped addrman
738 stream << *addrman_asmap1;
739 stream >> *addrman_noasmap;
740 AddressPosition addr_pos3 = addrman_noasmap->FindAddressEntry(addr).value();
741 BOOST_CHECK(addr_pos3.multiplicity != 0);
742 BOOST_CHECK(addr_pos1.bucket != addr_pos3.bucket);
743 BOOST_CHECK(addr_pos1.position != addr_pos3.position);
744
745 // deserializing non-asmaped peers.dat to asmaped addrman
746 addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
747 addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
748 addrman_noasmap->Add({addr}, default_source);
749 stream << *addrman_noasmap;
750 stream >> *addrman_asmap1;
751
752 AddressPosition addr_pos4 = addrman_asmap1->FindAddressEntry(addr).value();
753 BOOST_CHECK(addr_pos4.multiplicity != 0);
754 BOOST_CHECK(addr_pos4.bucket != addr_pos3.bucket);
755 BOOST_CHECK(addr_pos4 == addr_pos2);
756
757 // used to map to different buckets, now maps to the same bucket.
758 addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
759 addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
762 addrman_noasmap->Add({addr, addr2}, default_source);
763 AddressPosition addr_pos5 = addrman_noasmap->FindAddressEntry(addr1).value();
764 AddressPosition addr_pos6 = addrman_noasmap->FindAddressEntry(addr2).value();
765 BOOST_CHECK(addr_pos5.bucket != addr_pos6.bucket);
766 stream << *addrman_noasmap;
767 stream >> *addrman_asmap1;
768 AddressPosition addr_pos7 = addrman_asmap1->FindAddressEntry(addr1).value();
769 AddressPosition addr_pos8 = addrman_asmap1->FindAddressEntry(addr2).value();
770 BOOST_CHECK(addr_pos7.bucket == addr_pos8.bucket);
771 BOOST_CHECK(addr_pos7.position != addr_pos8.position);
772}
773
774BOOST_AUTO_TEST_CASE(remove_invalid)
775{
776 // Confirm that invalid addresses are ignored in unserialization.
777
778 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
779 DataStream stream{};
780
781 const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
782 const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
783 const CAddress tried1{ResolveService("7.7.7.7"), NODE_NONE};
784 const CAddress tried2{ResolveService("8.8.8.8"), NODE_NONE};
785
786 addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
787 addrman->Good(tried1);
788 addrman->Good(tried2);
789 BOOST_REQUIRE_EQUAL(addrman->Size(), 4);
790
791 stream << *addrman;
792
793 const std::string str{stream.str()};
794 size_t pos;
795
796 const char new2_raw[]{6, 6, 6, 6};
797 const uint8_t new2_raw_replacement[]{0, 0, 0, 0}; // 0.0.0.0 is !IsValid()
798 pos = str.find(new2_raw, 0, sizeof(new2_raw));
799 BOOST_REQUIRE(pos != std::string::npos);
800 BOOST_REQUIRE(pos + sizeof(new2_raw_replacement) <= stream.size());
801 memcpy(stream.data() + pos, new2_raw_replacement, sizeof(new2_raw_replacement));
802
803 const char tried2_raw[]{8, 8, 8, 8};
804 const uint8_t tried2_raw_replacement[]{255, 255, 255, 255}; // 255.255.255.255 is !IsValid()
805 pos = str.find(tried2_raw, 0, sizeof(tried2_raw));
806 BOOST_REQUIRE(pos != std::string::npos);
807 BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
808 memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
809
810 addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
811 stream >> *addrman;
812 BOOST_CHECK_EQUAL(addrman->Size(), 2);
813}
814
815BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
816{
817 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
818
819 BOOST_CHECK(addrman->Size() == 0);
820
821 // Empty addrman should return blank addrman info.
822 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
823
824 // Add twenty two addresses.
825 CNetAddr source = ResolveIP("252.2.2.2");
826 for (unsigned int i = 1; i < 23; i++) {
827 CService addr = ResolveService("250.1.1." + ToString(i));
828 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
829
830 // No collisions in tried.
831 BOOST_CHECK(addrman->Good(addr));
832 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
833 }
834
835 // Ensure Good handles duplicates well.
836 // If an address is a duplicate, Good will return false but will not count it as a collision.
837 for (unsigned int i = 1; i < 23; i++) {
838 CService addr = ResolveService("250.1.1." + ToString(i));
839
840 // Unable to add duplicate address to tried table.
841 BOOST_CHECK(!addrman->Good(addr));
842
843 // Verify duplicate address not marked as a collision.
844 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
845 }
846}
847
848BOOST_AUTO_TEST_CASE(addrman_noevict)
849{
850 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
851
852 // Add 35 addresses.
853 CNetAddr source = ResolveIP("252.2.2.2");
854 for (unsigned int i = 1; i < 36; i++) {
855 CService addr = ResolveService("250.1.1." + ToString(i));
856 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
857
858 // No collision yet.
859 BOOST_CHECK(addrman->Good(addr));
860 }
861
862 // Collision in tried table between 36 and 19.
863 CService addr36 = ResolveService("250.1.1.36");
864 BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source));
865 BOOST_CHECK(!addrman->Good(addr36));
866 BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.19:0");
867
868 // 36 should be discarded and 19 not evicted.
869 // This means we keep 19 in the tried table and
870 // 36 stays in the new table.
871 addrman->ResolveCollisions();
872 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
873
874 // Lets create two collisions.
875 for (unsigned int i = 37; i < 59; i++) {
876 CService addr = ResolveService("250.1.1." + ToString(i));
877 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
878 BOOST_CHECK(addrman->Good(addr));
879 }
880
881 // Cause a collision in the tried table.
882 CService addr59 = ResolveService("250.1.1.59");
883 BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source));
884 BOOST_CHECK(!addrman->Good(addr59));
885
886 BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.10:0");
887
888 // Cause a second collision in the new table.
889 BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source));
890
891 // 36 still cannot be moved from new to tried due to colliding with 19
892 BOOST_CHECK(!addrman->Good(addr36));
893 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() != "[::]:0");
894
895 // Resolve all collisions.
896 addrman->ResolveCollisions();
897 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
898}
899
900BOOST_AUTO_TEST_CASE(addrman_evictionworks)
901{
902 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
903
904 BOOST_CHECK(addrman->Size() == 0);
905
906 // Empty addrman should return blank addrman info.
907 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
908
909 // Add 35 addresses
910 CNetAddr source = ResolveIP("252.2.2.2");
911 for (unsigned int i = 1; i < 36; i++) {
912 CService addr = ResolveService("250.1.1." + ToString(i));
913 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
914
915 // No collision yet.
916 BOOST_CHECK(addrman->Good(addr));
917 }
918
919 // Collision between 36 and 19.
920 CService addr = ResolveService("250.1.1.36");
921 BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
922 BOOST_CHECK(!addrman->Good(addr));
923
924 auto info = addrman->SelectTriedCollision().first;
925 BOOST_CHECK_EQUAL(info.ToStringAddrPort(), "250.1.1.19:0");
926
927 // Ensure test of address fails, so that it is evicted.
928 // Update entry in tried by setting last good connection in the deep past.
929 BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
930 addrman->Attempt(info, /*fCountFailure=*/false, Now<NodeSeconds>() - 61s);
931
932 // Should swap 36 for 19.
933 addrman->ResolveCollisions();
934 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
935 AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
936 BOOST_CHECK(addr_pos.tried);
937
938 // If 36 was swapped for 19, then adding 36 to tried should fail because we
939 // are attempting to add a duplicate.
940 // We check this by verifying Good() returns false and also verifying that
941 // we have no collisions.
942 BOOST_CHECK(!addrman->Good(addr));
943 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
944
945 // 19 should fail as a collision (not a duplicate) if we now attempt to move
946 // it to the tried table.
947 CService addr19 = ResolveService("250.1.1.19");
948 BOOST_CHECK(!addrman->Good(addr19));
949 BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.36:0");
950
951 // Eviction is also successful if too much time has passed since last try
952 SetMockTime(GetTime() + 4 * 60 *60);
953 addrman->ResolveCollisions();
954 BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
955 //Now 19 is in tried again, and 36 back to new
956 AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()};
957 BOOST_CHECK(addr_pos19.tried);
958 AddressPosition addr_pos36{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
959 BOOST_CHECK(!addr_pos36.tried);
960}
961
962static auto AddrmanToStream(const AddrMan& addrman)
963{
964 DataStream ssPeersIn{};
965 ssPeersIn << Params().MessageStart();
966 ssPeersIn << addrman;
967 return ssPeersIn;
968}
969
971{
973
974 std::optional<CService> addr1, addr2, addr3, addr4;
975 addr1 = Lookup("250.7.1.1", 8333, false);
976 BOOST_CHECK(addr1.has_value());
977 addr2 = Lookup("250.7.2.2", 9999, false);
978 BOOST_CHECK(addr2.has_value());
979 addr3 = Lookup("250.7.3.3", 9999, false);
980 BOOST_CHECK(addr3.has_value());
981 addr3 = Lookup("250.7.3.3"s, 9999, false);
982 BOOST_CHECK(addr3.has_value());
983 addr4 = Lookup("250.7.3.3\0example.com"s, 9999, false);
984 BOOST_CHECK(!addr4.has_value());
985
986 // Add three addresses to new table.
987 const std::optional<CService> source{Lookup("252.5.1.1", 8333, false)};
988 BOOST_CHECK(source.has_value());
989 std::vector<CAddress> addresses{CAddress(addr1.value(), NODE_NONE), CAddress(addr2.value(), NODE_NONE), CAddress(addr3.value(), NODE_NONE)};
990 BOOST_CHECK(addrman.Add(addresses, source.value()));
991 BOOST_CHECK(addrman.Size() == 3);
992
993 // Test that the de-serialization does not throw an exception.
994 auto ssPeers1{AddrmanToStream(addrman)};
995 bool exceptionThrown = false;
997
998 BOOST_CHECK(addrman1.Size() == 0);
999 try {
1000 unsigned char pchMsgTmp[4];
1001 ssPeers1 >> pchMsgTmp;
1002 ssPeers1 >> addrman1;
1003 } catch (const std::exception&) {
1004 exceptionThrown = true;
1005 }
1006
1007 BOOST_CHECK(addrman1.Size() == 3);
1008 BOOST_CHECK(exceptionThrown == false);
1009
1010 // Test that ReadFromStream creates an addrman with the correct number of addrs.
1011 DataStream ssPeers2 = AddrmanToStream(addrman);
1012
1014 BOOST_CHECK(addrman2.Size() == 0);
1015 ReadFromStream(addrman2, ssPeers2);
1016 BOOST_CHECK(addrman2.Size() == 3);
1017}
1018
1019// Produce a corrupt peers.dat that claims 20 addrs when it only has one addr.
1021{
1022 DataStream s{};
1023 s << ::Params().MessageStart();
1024
1025 unsigned char nVersion = 1;
1026 s << nVersion;
1027 s << ((unsigned char)32);
1028 s << uint256::ONE;
1029 s << 10; // nNew
1030 s << 10; // nTried
1031
1032 int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
1033 s << nUBuckets;
1034
1035 const std::optional<CService> serv{Lookup("252.1.1.1", 7777, false)};
1036 BOOST_REQUIRE(serv.has_value());
1037 CAddress addr = CAddress(serv.value(), NODE_NONE);
1038 std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)};
1039 BOOST_REQUIRE(resolved.has_value());
1040 AddrInfo info = AddrInfo(addr, resolved.value());
1041 s << CAddress::V1_DISK(info);
1042
1043 return s;
1044}
1045
1046BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
1047{
1048 // Test that the de-serialization of corrupted peers.dat throws an exception.
1049 auto ssPeers1{MakeCorruptPeersDat()};
1050 bool exceptionThrown = false;
1052 BOOST_CHECK(addrman1.Size() == 0);
1053 try {
1054 unsigned char pchMsgTmp[4];
1055 ssPeers1 >> pchMsgTmp;
1056 ssPeers1 >> addrman1;
1057 } catch (const std::exception&) {
1058 exceptionThrown = true;
1059 }
1060 BOOST_CHECK(exceptionThrown);
1061
1062 // Test that ReadFromStream fails if peers.dat is corrupt
1063 auto ssPeers2{MakeCorruptPeersDat()};
1064
1066 BOOST_CHECK(addrman2.Size() == 0);
1067 BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
1068}
1069
1070BOOST_AUTO_TEST_CASE(addrman_update_address)
1071{
1072 // Tests updating nTime via Connected() and nServices via SetServices() and Add()
1073 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
1074 CNetAddr source{ResolveIP("252.2.2.2")};
1075 CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
1076
1077 const auto start_time{Now<NodeSeconds>() - 10000s};
1078 addr.nTime = start_time;
1079 BOOST_CHECK(addrman->Add({addr}, source));
1080 BOOST_CHECK_EQUAL(addrman->Size(), 1U);
1081
1082 // Updating an addrman entry with a different port doesn't change it
1083 CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)};
1084 addr_diff_port.nTime = start_time;
1085 addrman->Connected(addr_diff_port);
1086 addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
1087 std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1088 BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
1089 BOOST_CHECK(vAddr1.at(0).nTime == start_time);
1090 BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
1091
1092 // Updating an addrman entry with the correct port is successful
1093 addrman->Connected(addr);
1094 addrman->SetServices(addr, NODE_NETWORK_LIMITED);
1095 std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
1096 BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
1097 BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
1098 BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
1099
1100 // Updating an existing addr through Add() (used in gossip relay) can add additional services but can't remove existing ones.
1101 CAddress addr_v2{CAddress(ResolveService("250.1.1.1", 8333), NODE_P2P_V2)};
1102 addr_v2.nTime = start_time;
1103 BOOST_CHECK(!addrman->Add({addr_v2}, source));
1104 std::vector<CAddress> vAddr3{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1105 BOOST_CHECK_EQUAL(vAddr3.size(), 1U);
1106 BOOST_CHECK_EQUAL(vAddr3.at(0).nServices, NODE_P2P_V2 | NODE_NETWORK_LIMITED);
1107
1108 // SetServices() (used when we connected to them) overwrites existing service flags
1109 addrman->SetServices(addr, NODE_NETWORK);
1110 std::vector<CAddress> vAddr4{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1111 BOOST_CHECK_EQUAL(vAddr4.size(), 1U);
1112 BOOST_CHECK_EQUAL(vAddr4.at(0).nServices, NODE_NETWORK);
1113
1114 // Promoting to Tried does not affect the service flags
1115 BOOST_CHECK(addrman->Good(addr)); // addr has NODE_NONE
1116 std::vector<CAddress> vAddr5{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1117 BOOST_CHECK_EQUAL(vAddr5.size(), 1U);
1118 BOOST_CHECK_EQUAL(vAddr5.at(0).nServices, NODE_NETWORK);
1119
1120 // Adding service flags even works when the addr is in Tried
1121 BOOST_CHECK(!addrman->Add({addr_v2}, source));
1122 std::vector<CAddress> vAddr6{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
1123 BOOST_CHECK_EQUAL(vAddr6.size(), 1U);
1124 BOOST_CHECK_EQUAL(vAddr6.at(0).nServices, NODE_NETWORK | NODE_P2P_V2);
1125}
1126
1128{
1129 auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
1130 const CNetAddr source = ResolveIP("252.2.2.2");
1131
1132 // empty addrman
1133 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 0U);
1134 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 0U);
1135 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 0U);
1136 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 0U);
1137
1138 // add two ipv4 addresses, one to tried and new
1139 const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
1140 BOOST_CHECK(addrman->Add({addr1}, source));
1141 BOOST_CHECK(addrman->Good(addr1));
1142 const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
1143 BOOST_CHECK(addrman->Add({addr2}, source));
1144
1145 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 2U);
1146 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1147 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 1U);
1148 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1149 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/true), 1U);
1150 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/false), 1U);
1151
1152 // add one i2p address to new
1153 CService i2p_addr;
1154 i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
1155 const CAddress addr3{i2p_addr, NODE_NONE};
1156 BOOST_CHECK(addrman->Add({addr3}, source));
1157 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/std::nullopt), 3U);
1158 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_IPV4, /*in_new=*/std::nullopt), 2U);
1159 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/std::nullopt), 1U);
1160 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/NET_I2P, /*in_new=*/true), 1U);
1161 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/true), 2U);
1162 BOOST_CHECK_EQUAL(addrman->Size(/*net=*/std::nullopt, /*in_new=*/false), 1U);
1163}
1164
void ReadFromStream(AddrMan &addr, DataStream &ssPeers)
Only used by tests.
Definition addrdb.cpp:186
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
static NetGroupManager EMPTY_NETGROUPMAN
static std::vector< bool > FromBytes(const unsigned char *source, int vector_size)
static CService ResolveService(const std::string &ip, uint16_t port=0)
static int32_t GetCheckRatio(const NodeContext &node_ctx)
static auto AddrmanToStream(const AddrMan &addrman)
static const bool DETERMINISTIC
BOOST_AUTO_TEST_CASE(addrman_simple)
static auto MakeCorruptPeersDat()
static CNetAddr ResolveIP(const std::string &ip)
static unsigned const char asmap_raw[]
Definition asmap.raw.h:1
node::NodeContext m_node
const CChainParams & Params()
Return the currently selected parameters.
Extended statistics about a CAddress.
int GetNewBucket(const uint256 &nKey, const CNetAddr &src, const NetGroupManager &netgroupman) const
Calculate in which "new" bucket this entry belongs, given a certain source.
Definition addrman.cpp:55
int GetTriedBucket(const uint256 &nKey, const NetGroupManager &netgroupman) const
Calculate in which "tried" bucket this entry belongs.
Definition addrman.cpp:48
Stochastic address manager.
Definition addrman.h:88
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition args.cpp:481
A CService with information about it as peer.
Definition protocol.h:367
NodeSeconds nTime
Always included in serialization. The behavior is unspecified if the value is not representable as ui...
Definition protocol.h:457
static constexpr SerParams V1_DISK
Definition protocol.h:410
const MessageStartChars & MessageStart() const
Definition chainparams.h:94
Network address.
Definition netaddress.h:112
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
A combination of a network address (CNetAddr) and a (TCP) port.
Definition netaddress.h:531
std::vector< unsigned char > GetKey() const
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:147
A writer stream (for serialization) that computes a 256-bit hash.
Definition hash.h:101
Netgroup manager.
Definition netgroup.h:16
256-bit opaque blob.
Definition uint256.h:178
static const uint256 ONE
Definition uint256.h:186
BOOST_AUTO_TEST_SUITE_END()
static CService ip(uint32_t i)
static const std::string addr1
Definition key_tests.cpp:29
static const std::string addr2
Definition key_tests.cpp:30
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition string.h:156
@ NET_I2P
I2P.
Definition netaddress.h:46
@ NET_CJDNS
CJDNS.
Definition netaddress.h:49
@ NET_ONION
TOR (v2 or v3)
Definition netaddress.h:43
@ NET_IPV6
IPv6.
Definition netaddress.h:40
@ NET_IPV4
IPv4.
Definition netaddress.h:37
std::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition netbase.cpp:177
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition netbase.cpp:195
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition object.cpp:19
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:18
#define BOOST_CHECK(expr)
Definition object.cpp:17
@ NODE_NONE
Definition protocol.h:312
@ NODE_P2P_V2
Definition protocol.h:330
@ NODE_NETWORK_LIMITED
Definition protocol.h:327
@ NODE_NETWORK
Definition protocol.h:315
const char * source
Location information for an address in AddrMan.
Definition addrman.h:34
const int bucket
Definition addrman.h:47
const int position
Definition addrman.h:48
const int multiplicity
Definition addrman.h:41
Basic testing setup.
NodeContext struct containing references to chain state and connection state.
Definition context.h:55
ArgsManager * args
Definition context.h:71
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition time.cpp:44
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition time.cpp:32
T Now()
Return the current time point cast to the given precision.
Definition time.h:91
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition time.h:23
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...