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