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