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