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