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