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