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