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