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