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