Bitcoin Core  29.1.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 using util::ToString;
26 
27 static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
28 static const bool DETERMINISTIC{true};
29 
30 static int32_t GetCheckRatio(const NodeContext& node_ctx)
31 {
32  return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
33 }
34 
35 static 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 
42 static 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 
50 static 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 
65 BOOST_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 
109 BOOST_AUTO_TEST_CASE(addrman_ports)
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 
137 BOOST_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 
196 BOOST_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 
264 BOOST_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 
287 BOOST_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 
316 BOOST_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 
348 BOOST_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 
379 BOOST_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 
438 BOOST_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 
468 BOOST_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());
492  BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));
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 
519 BOOST_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());
542  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));
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
593 BOOST_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 
647 BOOST_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 
725 BOOST_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 
790 BOOST_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 
831 BOOST_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 
864 BOOST_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 
916 BOOST_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 
978 static auto AddrmanToStream(const AddrMan& addrman)
979 {
980  DataStream ssPeersIn{};
981  ssPeersIn << Params().MessageStart();
982  ssPeersIn << addrman;
983  return ssPeersIn;
984 }
985 
986 BOOST_AUTO_TEST_CASE(load_addrman)
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.
1036 static auto MakeCorruptPeersDat()
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 
1062 BOOST_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 
1086 BOOST_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 
static const uint256 ONE
Definition: uint256.h:210
static auto AddrmanToStream(const AddrMan &addrman)
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition: object.cpp:19
node::NodeContext m_node
Definition: bitcoin-gui.cpp:42
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
IPv4.
Definition: netaddress.h:37
static const bool DETERMINISTIC
static constexpr SerParams V1_DISK
Definition: protocol.h:410
memcpy(result.begin(), stream.data(), stream.size())
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
Definition: netaddress.cpp:211
Netgroup manager.
Definition: netgroup.h:16
static CService ResolveService(const std::string &ip, uint16_t port=0)
I2P.
Definition: netaddress.h:46
BOOST_AUTO_TEST_CASE(addrman_simple)
Stochastic address manager.
Definition: addrman.h:88
Basic testing setup.
Definition: setup_common.h:64
std::chrono::time_point< NodeClock, std::chrono::seconds > NodeSeconds
Definition: time.h:25
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:40
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
const int bucket
Definition: addrman.h:48
const char * source
Definition: rpcconsole.cpp:62
static const std::string addr2
Definition: key_tests.cpp:31
static const std::string addr1
Definition: key_tests.cpp:30
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
static NetGroupManager EMPTY_NETGROUPMAN
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
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
ArgsManager * args
Definition: context.h:74
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:530
BOOST_AUTO_TEST_SUITE_END()
Extended statistics about a CAddress.
Definition: addrman_impl.h:45
A CService with information about it as peer.
Definition: protocol.h:366
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:899
static CService ip(uint32_t i)
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
NodeSeconds nTime
Always included in serialization. The behavior is unspecified if the value is not representable as ui...
Definition: protocol.h:457
const int position
Definition: addrman.h:49
const int multiplicity
Definition: addrman.h:42
Network address.
Definition: netaddress.h:111
void ReadFromStream(AddrMan &addr, DataStream &ssPeers)
Only used by tests.
Definition: addrdb.cpp:186
256-bit opaque blob.
Definition: uint256.h:201
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
auto result
Definition: common-types.h:74
static auto MakeCorruptPeersDat()
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman_impl.h:30
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
const CChainParams & Params()
Return the currently selected parameters.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:482
const MessageStartChars & MessageStart() const
Definition: chainparams.h:94
IPv6.
Definition: netaddress.h:40
TOR (v2 or v3)
Definition: netaddress.h:43
static int32_t GetCheckRatio(const NodeContext &node_ctx)
Location information for an address in AddrMan.
Definition: addrman.h:35
int64_t GetTime()
DEPRECATED, see GetTime.
Definition: time.cpp:76
int GetTriedBucket(const uint256 &nKey, const NetGroupManager &netgroupman) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:48
CJDNS.
Definition: netaddress.h:49
static CNetAddr ResolveIP(const std::string &ip)
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:233
#define BOOST_CHECK(expr)
Definition: object.cpp:17
static std::vector< bool > FromBytes(std::span< const std::byte > source)