Bitcoin Core  22.99.0
P2P Digital Currency
addrman_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2021 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <addrdb.h>
6 #include <addrman.h>
7 #include <addrman_impl.h>
8 #include <chainparams.h>
9 #include <clientversion.h>
10 #include <hash.h>
11 #include <netbase.h>
12 #include <random.h>
13 #include <test/data/asmap.raw.h>
14 #include <test/util/setup_common.h>
15 #include <util/asmap.h>
16 #include <util/string.h>
17 
18 #include <boost/test/unit_test.hpp>
19 
20 #include <optional>
21 #include <string>
22 
23 using namespace std::literals;
24 using node::NodeContext;
25 
26 static const std::vector<bool> EMPTY_ASMAP;
27 static const bool DETERMINISTIC{true};
28 
29 static int32_t GetCheckRatio(const NodeContext& node_ctx)
30 {
31  return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
32 }
33 
34 static CNetAddr ResolveIP(const std::string& ip)
35 {
36  CNetAddr addr;
37  BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip));
38  return addr;
39 }
40 
41 static CService ResolveService(const std::string& ip, uint16_t port = 0)
42 {
43  CService serv;
44  BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
45  return serv;
46 }
47 
48 
49 static std::vector<bool> FromBytes(const unsigned char* source, int vector_size)
50 {
51  std::vector<bool> result(vector_size);
52  for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) {
53  unsigned char cur_byte = source[byte_i];
54  for (int bit_i = 0; bit_i < 8; ++bit_i) {
55  result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1;
56  }
57  }
58  return result;
59 }
60 
62 
63 BOOST_AUTO_TEST_CASE(addrman_simple)
64 {
65  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
66 
67  CNetAddr source = ResolveIP("252.2.2.2");
68 
69  // Test: Does Addrman respond correctly when empty.
70  BOOST_CHECK_EQUAL(addrman->size(), 0U);
71  auto addr_null = addrman->Select().first;
72  BOOST_CHECK_EQUAL(addr_null.ToString(), "[::]:0");
73 
74  // Test: Does Addrman::Add work as expected.
75  CService addr1 = ResolveService("250.1.1.1", 8333);
76  BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
77  BOOST_CHECK_EQUAL(addrman->size(), 1U);
78  auto addr_ret1 = addrman->Select().first;
79  BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
80 
81  // Test: Does IP address deduplication work correctly.
82  // Expected dup IP should not be added.
83  CService addr1_dup = ResolveService("250.1.1.1", 8333);
84  BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
85  BOOST_CHECK_EQUAL(addrman->size(), 1U);
86 
87 
88  // Test: New table has one addr and we add a diff addr we should
89  // have at least one addr.
90  // Note that addrman's size cannot be tested reliably after insertion, as
91  // hash collisions may occur. But we can always be sure of at least one
92  // success.
93 
94  CService addr2 = ResolveService("250.1.1.2", 8333);
95  BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
96  BOOST_CHECK(addrman->size() >= 1);
97 
98  // Test: reset addrman and test AddrMan::Add multiple addresses works as expected
99  addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
100  std::vector<CAddress> vAddr;
101  vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
102  vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
103  BOOST_CHECK(addrman->Add(vAddr, source));
104  BOOST_CHECK(addrman->size() >= 1);
105 }
106 
107 BOOST_AUTO_TEST_CASE(addrman_ports)
108 {
109  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
110 
111  CNetAddr source = ResolveIP("252.2.2.2");
112 
113  BOOST_CHECK_EQUAL(addrman->size(), 0U);
114 
115  // Test 7; Addr with same IP but diff port does not replace existing addr.
116  CService addr1 = ResolveService("250.1.1.1", 8333);
117  BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
118  BOOST_CHECK_EQUAL(addrman->size(), 1U);
119 
120  CService addr1_port = ResolveService("250.1.1.1", 8334);
121  BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));
122  BOOST_CHECK_EQUAL(addrman->size(), 2U);
123  auto addr_ret2 = addrman->Select().first;
124  BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333" || addr_ret2.ToString() == "250.1.1.1:8334");
125 
126  // Test: Add same IP but diff port to tried table; this converts the entry with
127  // the specified port to tried, but not the other.
128  addrman->Good(CAddress(addr1_port, NODE_NONE));
129  BOOST_CHECK_EQUAL(addrman->size(), 2U);
130  bool newOnly = true;
131  auto addr_ret3 = addrman->Select(newOnly).first;
132  BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
133 }
134 
135 
136 BOOST_AUTO_TEST_CASE(addrman_select)
137 {
138  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
139 
140  CNetAddr source = ResolveIP("252.2.2.2");
141 
142  // Test: Select from new with 1 addr in new.
143  CService addr1 = ResolveService("250.1.1.1", 8333);
144  BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
145  BOOST_CHECK_EQUAL(addrman->size(), 1U);
146 
147  bool newOnly = true;
148  auto addr_ret1 = addrman->Select(newOnly).first;
149  BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
150 
151  // Test: move addr to tried, select from new expected nothing returned.
152  BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
153  BOOST_CHECK_EQUAL(addrman->size(), 1U);
154  auto addr_ret2 = addrman->Select(newOnly).first;
155  BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0");
156 
157  auto addr_ret3 = addrman->Select().first;
158  BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
159 
160  BOOST_CHECK_EQUAL(addrman->size(), 1U);
161 
162 
163  // Add three addresses to new table.
164  CService addr2 = ResolveService("250.3.1.1", 8333);
165  CService addr3 = ResolveService("250.3.2.2", 9999);
166  CService addr4 = ResolveService("250.3.3.3", 9999);
167 
168  BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
169  BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
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)}, ResolveService("250.3.1.1", 8333)));
178  BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));
179  BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
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  // Test: 6 addrs + 1 addr from last test = 7.
185  BOOST_CHECK_EQUAL(addrman->size(), 7U);
186 
187  // Test: 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_new_collisions)
196 {
197  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
198 
199  CNetAddr source = ResolveIP("252.2.2.2");
200 
201  uint32_t num_addrs{0};
202 
203  BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
204 
205  while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
206  CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
207  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
208 
209  // Test: No collision in new table yet.
210  BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
211  }
212 
213  // Test: new table collision!
214  CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
215  uint32_t collisions{1};
216  BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
217  BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions);
218 
219  CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
220  BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
221  BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions);
222 }
223 
224 BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
225 {
226  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
227  CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
228  int64_t start_time{GetAdjustedTime()};
229  addr.nTime = start_time;
230 
231  // test that multiplicity stays at 1 if nTime doesn't increase
232  for (unsigned int i = 1; i < 20; ++i) {
233  std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
234  CNetAddr source{ResolveIP(addr_ip)};
235  addrman->Add({addr}, source);
236  }
237  AddressPosition addr_pos = addrman->FindAddressEntry(addr).value();
238  BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U);
239  BOOST_CHECK_EQUAL(addrman->size(), 1U);
240 
241  // if nTime increases, an addr can occur in up to 8 buckets
242  // The acceptance probability decreases exponentially with existing multiplicity -
243  // choose number of iterations such that it gets to 8 with deterministic addrman.
244  for (unsigned int i = 1; i < 400; ++i) {
245  std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
246  CNetAddr source{ResolveIP(addr_ip)};
247  addr.nTime = start_time + i;
248  addrman->Add({addr}, source);
249  }
250  AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
251  BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U);
252  // multiplicity doesn't affect size
253  BOOST_CHECK_EQUAL(addrman->size(), 1U);
254 }
255 
256 BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
257 {
258  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
259 
260  CNetAddr source = ResolveIP("252.2.2.2");
261 
262  uint32_t num_addrs{0};
263 
264  BOOST_CHECK_EQUAL(addrman->size(), num_addrs);
265 
266  while (num_addrs < 35) { // Magic number! 250.1.1.1 - 250.1.1.35 do not collide in tried with deterministic key = 1
267  CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
268  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
269 
270  // Test: Add to tried without collision
271  BOOST_CHECK(addrman->Good(CAddress(addr, NODE_NONE)));
272 
273  }
274 
275  // Test: Unable to add to tried table due to collision!
276  CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
277  BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
278  BOOST_CHECK(!addrman->Good(CAddress(addr1, NODE_NONE)));
279 
280  // Test: Add the next address to tried without collision
281  CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
282  BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
283  BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
284 }
285 
286 
287 BOOST_AUTO_TEST_CASE(addrman_getaddr)
288 {
289  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
290 
291  // Test: Sanity check, GetAddr should never return anything if addrman
292  // is empty.
293  BOOST_CHECK_EQUAL(addrman->size(), 0U);
294  std::vector<CAddress> vAddr1 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
295  BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
296 
297  CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
298  addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
299  CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
300  addr2.nTime = GetAdjustedTime();
301  CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
302  addr3.nTime = GetAdjustedTime();
303  CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
304  addr4.nTime = GetAdjustedTime();
305  CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
306  addr5.nTime = GetAdjustedTime();
307  CNetAddr source1 = ResolveIP("250.1.2.1");
308  CNetAddr source2 = ResolveIP("250.2.3.3");
309 
310  // Test: Ensure GetAddr works with new addresses.
311  BOOST_CHECK(addrman->Add({addr1, addr3, addr5}, source1));
312  BOOST_CHECK(addrman->Add({addr2, addr4}, source2));
313 
314  BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
315  // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
316  BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
317 
318  // Test: Ensure GetAddr works with new and tried addresses.
319  BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
320  BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
321  BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U);
322  BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U);
323 
324  // Test: Ensure GetAddr still returns 23% when addrman has many addrs.
325  for (unsigned int i = 1; i < (8 * 256); i++) {
326  int octet1 = i % 256;
327  int octet2 = i >> 8 % 256;
328  std::string strAddr = ToString(octet1) + "." + ToString(octet2) + ".1.23";
329  CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
330 
331  // Ensure that for all addrs in addrman, isTerrible == false.
332  addr.nTime = GetAdjustedTime();
333  addrman->Add({addr}, ResolveIP(strAddr));
334  if (i % 8 == 0)
335  addrman->Good(addr);
336  }
337  std::vector<CAddress> vAddr = addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
338 
339  size_t percent23 = (addrman->size() * 23) / 100;
340  BOOST_CHECK_EQUAL(vAddr.size(), percent23);
341  BOOST_CHECK_EQUAL(vAddr.size(), 461U);
342  // (Addrman.size() < number of addresses added) due to address collisions.
343  BOOST_CHECK_EQUAL(addrman->size(), 2006U);
344 }
345 
346 
347 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
348 {
349  CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
350  CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
351 
352  CNetAddr source1 = ResolveIP("250.1.1.1");
353 
354 
355  AddrInfo info1 = AddrInfo(addr1, source1);
356 
357  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
358  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
359 
360  std::vector<bool> asmap; // use /16
361 
362  BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40);
363 
364  // Test: Make sure key actually randomizes bucket placement. A fail on
365  // this test could be a security issue.
366  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
367 
368  // Test: Two addresses with same IP but different ports can map to
369  // different buckets because they have different keys.
370  AddrInfo info2 = AddrInfo(addr2, source1);
371 
372  BOOST_CHECK(info1.GetKey() != info2.GetKey());
373  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
374 
375  std::set<int> buckets;
376  for (int i = 0; i < 255; i++) {
377  AddrInfo infoi = AddrInfo(
378  CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
379  ResolveIP("250.1.1." + ToString(i)));
380  int bucket = infoi.GetTriedBucket(nKey1, asmap);
381  buckets.insert(bucket);
382  }
383  // Test: IP addresses in the same /16 prefix should
384  // never get more than 8 buckets with legacy grouping
385  BOOST_CHECK_EQUAL(buckets.size(), 8U);
386 
387  buckets.clear();
388  for (int j = 0; j < 255; j++) {
389  AddrInfo infoj = AddrInfo(
390  CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
391  ResolveIP("250." + ToString(j) + ".1.1"));
392  int bucket = infoj.GetTriedBucket(nKey1, asmap);
393  buckets.insert(bucket);
394  }
395  // Test: IP addresses in the different /16 prefix should map to more than
396  // 8 buckets with legacy grouping
397  BOOST_CHECK_EQUAL(buckets.size(), 160U);
398 }
399 
400 BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
401 {
402  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
403  CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
404 
405  CNetAddr source1 = ResolveIP("250.1.2.1");
406 
407  AddrInfo info1 = AddrInfo(addr1, source1);
408 
409  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
410  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
411 
412  std::vector<bool> asmap; // use /16
413 
414  // Test: Make sure the buckets are what we expect
415  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786);
416  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786);
417 
418  // Test: Make sure key actually randomizes bucket placement. A fail on
419  // this test could be a security issue.
420  BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
421 
422  // Test: Ports should not affect bucket placement in the addr
423  AddrInfo info2 = AddrInfo(addr2, source1);
424  BOOST_CHECK(info1.GetKey() != info2.GetKey());
425  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
426 
427  std::set<int> buckets;
428  for (int i = 0; i < 255; i++) {
429  AddrInfo infoi = AddrInfo(
430  CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
431  ResolveIP("250.1.1." + ToString(i)));
432  int bucket = infoi.GetNewBucket(nKey1, asmap);
433  buckets.insert(bucket);
434  }
435  // Test: IP addresses in the same group (\16 prefix for IPv4) should
436  // always map to the same bucket.
437  BOOST_CHECK_EQUAL(buckets.size(), 1U);
438 
439  buckets.clear();
440  for (int j = 0; j < 4 * 255; j++) {
441  AddrInfo infoj = AddrInfo(CAddress(
443  ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
444  ResolveIP("251.4.1.1"));
445  int bucket = infoj.GetNewBucket(nKey1, asmap);
446  buckets.insert(bucket);
447  }
448  // Test: IP addresses in the same source groups should map to NO MORE
449  // than 64 buckets.
450  BOOST_CHECK(buckets.size() <= 64);
451 
452  buckets.clear();
453  for (int p = 0; p < 255; p++) {
454  AddrInfo infoj = AddrInfo(
455  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
456  ResolveIP("250." + ToString(p) + ".1.1"));
457  int bucket = infoj.GetNewBucket(nKey1, asmap);
458  buckets.insert(bucket);
459  }
460  // Test: IP addresses in the different source groups should map to MORE
461  // than 64 buckets.
462  BOOST_CHECK(buckets.size() > 64);
463 }
464 
465 // The following three test cases use asmap.raw
466 // We use an artificial minimal mock mapping
467 // 250.0.0.0/8 AS1000
468 // 101.1.0.0/16 AS1
469 // 101.2.0.0/16 AS2
470 // 101.3.0.0/16 AS3
471 // 101.4.0.0/16 AS4
472 // 101.5.0.0/16 AS5
473 // 101.6.0.0/16 AS6
474 // 101.7.0.0/16 AS7
475 // 101.8.0.0/16 AS8
476 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
477 {
478  CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
479  CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
480 
481  CNetAddr source1 = ResolveIP("250.1.1.1");
482 
483 
484  AddrInfo info1 = AddrInfo(addr1, source1);
485 
486  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
487  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
488 
489  std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
490 
491  BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236);
492 
493  // Test: Make sure key actually randomizes bucket placement. A fail on
494  // this test could be a security issue.
495  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
496 
497  // Test: Two addresses with same IP but different ports can map to
498  // different buckets because they have different keys.
499  AddrInfo info2 = AddrInfo(addr2, source1);
500 
501  BOOST_CHECK(info1.GetKey() != info2.GetKey());
502  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
503 
504  std::set<int> buckets;
505  for (int j = 0; j < 255; j++) {
506  AddrInfo infoj = AddrInfo(
507  CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
508  ResolveIP("101." + ToString(j) + ".1.1"));
509  int bucket = infoj.GetTriedBucket(nKey1, asmap);
510  buckets.insert(bucket);
511  }
512  // Test: IP addresses in the different /16 prefix MAY map to more than
513  // 8 buckets.
514  BOOST_CHECK(buckets.size() > 8);
515 
516  buckets.clear();
517  for (int j = 0; j < 255; j++) {
518  AddrInfo infoj = AddrInfo(
519  CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
520  ResolveIP("250." + ToString(j) + ".1.1"));
521  int bucket = infoj.GetTriedBucket(nKey1, asmap);
522  buckets.insert(bucket);
523  }
524  // Test: IP addresses in the different /16 prefix MAY NOT map to more than
525  // 8 buckets.
526  BOOST_CHECK(buckets.size() == 8);
527 }
528 
529 BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
530 {
531  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
532  CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
533 
534  CNetAddr source1 = ResolveIP("250.1.2.1");
535 
536  AddrInfo info1 = AddrInfo(addr1, source1);
537 
538  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
539  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
540 
541  std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
542 
543  // Test: Make sure the buckets are what we expect
544  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795);
545  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795);
546 
547  // Test: Make sure key actually randomizes bucket placement. A fail on
548  // this test could be a security issue.
549  BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
550 
551  // Test: Ports should not affect bucket placement in the addr
552  AddrInfo info2 = AddrInfo(addr2, source1);
553  BOOST_CHECK(info1.GetKey() != info2.GetKey());
554  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
555 
556  std::set<int> buckets;
557  for (int i = 0; i < 255; i++) {
558  AddrInfo infoi = AddrInfo(
559  CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
560  ResolveIP("250.1.1." + ToString(i)));
561  int bucket = infoi.GetNewBucket(nKey1, asmap);
562  buckets.insert(bucket);
563  }
564  // Test: IP addresses in the same /16 prefix
565  // usually map to the same bucket.
566  BOOST_CHECK_EQUAL(buckets.size(), 1U);
567 
568  buckets.clear();
569  for (int j = 0; j < 4 * 255; j++) {
570  AddrInfo infoj = AddrInfo(CAddress(
572  ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
573  ResolveIP("251.4.1.1"));
574  int bucket = infoj.GetNewBucket(nKey1, asmap);
575  buckets.insert(bucket);
576  }
577  // Test: IP addresses in the same source /16 prefix should not map to more
578  // than 64 buckets.
579  BOOST_CHECK(buckets.size() <= 64);
580 
581  buckets.clear();
582  for (int p = 0; p < 255; p++) {
583  AddrInfo infoj = AddrInfo(
584  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
585  ResolveIP("101." + ToString(p) + ".1.1"));
586  int bucket = infoj.GetNewBucket(nKey1, asmap);
587  buckets.insert(bucket);
588  }
589  // Test: IP addresses in the different source /16 prefixes usually map to MORE
590  // than 1 bucket.
591  BOOST_CHECK(buckets.size() > 1);
592 
593  buckets.clear();
594  for (int p = 0; p < 255; p++) {
595  AddrInfo infoj = AddrInfo(
596  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
597  ResolveIP("250." + ToString(p) + ".1.1"));
598  int bucket = infoj.GetNewBucket(nKey1, asmap);
599  buckets.insert(bucket);
600  }
601  // Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
602  // than 1 bucket.
603  BOOST_CHECK(buckets.size() == 1);
604 }
605 
606 BOOST_AUTO_TEST_CASE(addrman_serialization)
607 {
608  std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
609 
610  const auto ratio = GetCheckRatio(m_node);
611  auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
612  auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
613  auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
614 
616 
617  CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
618  CNetAddr default_source;
619 
620  addrman_asmap1->Add({addr}, default_source);
621 
622  stream << *addrman_asmap1;
623  // serizalizing/deserializing addrman with the same asmap
624  stream >> *addrman_asmap1_dup;
625 
626  AddressPosition addr_pos1 = addrman_asmap1->FindAddressEntry(addr).value();
627  AddressPosition addr_pos2 = addrman_asmap1_dup->FindAddressEntry(addr).value();
628  BOOST_CHECK(addr_pos1.multiplicity != 0);
629  BOOST_CHECK(addr_pos2.multiplicity != 0);
630 
631  BOOST_CHECK(addr_pos1 == addr_pos2);
632 
633  // deserializing asmaped peers.dat to non-asmaped addrman
634  stream << *addrman_asmap1;
635  stream >> *addrman_noasmap;
636  AddressPosition addr_pos3 = addrman_noasmap->FindAddressEntry(addr).value();
637  BOOST_CHECK(addr_pos3.multiplicity != 0);
638  BOOST_CHECK(addr_pos1.bucket != addr_pos3.bucket);
639  BOOST_CHECK(addr_pos1.position != addr_pos3.position);
640 
641  // deserializing non-asmaped peers.dat to asmaped addrman
642  addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
643  addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
644  addrman_noasmap->Add({addr}, default_source);
645  stream << *addrman_noasmap;
646  stream >> *addrman_asmap1;
647 
648  AddressPosition addr_pos4 = addrman_asmap1->FindAddressEntry(addr).value();
649  BOOST_CHECK(addr_pos4.multiplicity != 0);
650  BOOST_CHECK(addr_pos4.bucket != addr_pos3.bucket);
651  BOOST_CHECK(addr_pos4 == addr_pos2);
652 
653  // used to map to different buckets, now maps to the same bucket.
654  addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
655  addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
658  addrman_noasmap->Add({addr, addr2}, default_source);
659  AddressPosition addr_pos5 = addrman_noasmap->FindAddressEntry(addr1).value();
660  AddressPosition addr_pos6 = addrman_noasmap->FindAddressEntry(addr2).value();
661  BOOST_CHECK(addr_pos5.bucket != addr_pos6.bucket);
662  stream << *addrman_noasmap;
663  stream >> *addrman_asmap1;
664  AddressPosition addr_pos7 = addrman_asmap1->FindAddressEntry(addr1).value();
665  AddressPosition addr_pos8 = addrman_asmap1->FindAddressEntry(addr2).value();
666  BOOST_CHECK(addr_pos7.bucket == addr_pos8.bucket);
667  BOOST_CHECK(addr_pos7.position != addr_pos8.position);
668 }
669 
670 BOOST_AUTO_TEST_CASE(remove_invalid)
671 {
672  // Confirm that invalid addresses are ignored in unserialization.
673 
674  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
676 
677  const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
678  const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
679  const CAddress tried1{ResolveService("7.7.7.7"), NODE_NONE};
680  const CAddress tried2{ResolveService("8.8.8.8"), NODE_NONE};
681 
682  addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
683  addrman->Good(tried1);
684  addrman->Good(tried2);
685  BOOST_REQUIRE_EQUAL(addrman->size(), 4);
686 
687  stream << *addrman;
688 
689  const std::string str{stream.str()};
690  size_t pos;
691 
692  const char new2_raw[]{6, 6, 6, 6};
693  const uint8_t new2_raw_replacement[]{0, 0, 0, 0}; // 0.0.0.0 is !IsValid()
694  pos = str.find(new2_raw, 0, sizeof(new2_raw));
695  BOOST_REQUIRE(pos != std::string::npos);
696  BOOST_REQUIRE(pos + sizeof(new2_raw_replacement) <= stream.size());
697  memcpy(stream.data() + pos, new2_raw_replacement, sizeof(new2_raw_replacement));
698 
699  const char tried2_raw[]{8, 8, 8, 8};
700  const uint8_t tried2_raw_replacement[]{255, 255, 255, 255}; // 255.255.255.255 is !IsValid()
701  pos = str.find(tried2_raw, 0, sizeof(tried2_raw));
702  BOOST_REQUIRE(pos != std::string::npos);
703  BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
704  memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
705 
706  addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
707  stream >> *addrman;
708  BOOST_CHECK_EQUAL(addrman->size(), 2);
709 }
710 
711 BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
712 {
713  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
714 
715  BOOST_CHECK(addrman->size() == 0);
716 
717  // Empty addrman should return blank addrman info.
718  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
719 
720  // Add twenty two addresses.
721  CNetAddr source = ResolveIP("252.2.2.2");
722  for (unsigned int i = 1; i < 23; i++) {
723  CService addr = ResolveService("250.1.1." + ToString(i));
724  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
725 
726  // No collisions in tried.
727  BOOST_CHECK(addrman->Good(addr));
728  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
729  }
730 
731  // Ensure Good handles duplicates well.
732  // If an address is a duplicate, Good will return false but will not count it as a collision.
733  for (unsigned int i = 1; i < 23; i++) {
734  CService addr = ResolveService("250.1.1." + ToString(i));
735 
736  // Unable to add duplicate address to tried table.
737  BOOST_CHECK(!addrman->Good(addr));
738 
739  // Verify duplicate address not marked as a collision.
740  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
741  }
742 }
743 
744 BOOST_AUTO_TEST_CASE(addrman_noevict)
745 {
746  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
747 
748  // Add 35 addresses.
749  CNetAddr source = ResolveIP("252.2.2.2");
750  for (unsigned int i = 1; i < 36; i++) {
751  CService addr = ResolveService("250.1.1." + ToString(i));
752  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
753 
754  // No collision yet.
755  BOOST_CHECK(addrman->Good(addr));
756  }
757 
758  // Collision in tried table between 36 and 19.
759  CService addr36 = ResolveService("250.1.1.36");
760  BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source));
761  BOOST_CHECK(!addrman->Good(addr36));
762  BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.19:0");
763 
764  // 36 should be discarded and 19 not evicted.
765  // This means we keep 19 in the tried table and
766  // 36 stays in the new table.
767  addrman->ResolveCollisions();
768  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
769 
770  // Lets create two collisions.
771  for (unsigned int i = 37; i < 59; i++) {
772  CService addr = ResolveService("250.1.1." + ToString(i));
773  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
774  BOOST_CHECK(addrman->Good(addr));
775  }
776 
777  // Cause a collision in the tried table.
778  CService addr59 = ResolveService("250.1.1.59");
779  BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source));
780  BOOST_CHECK(!addrman->Good(addr59));
781 
782  BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.10:0");
783 
784  // Cause a second collision in the new table.
785  BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source));
786 
787  // 36 still cannot be moved from new to tried due to colliding with 19
788  BOOST_CHECK(!addrman->Good(addr36));
789  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() != "[::]:0");
790 
791  // Resolve all collisions.
792  addrman->ResolveCollisions();
793  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
794 }
795 
796 BOOST_AUTO_TEST_CASE(addrman_evictionworks)
797 {
798  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
799 
800  BOOST_CHECK(addrman->size() == 0);
801 
802  // Empty addrman should return blank addrman info.
803  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
804 
805  // Add 35 addresses
806  CNetAddr source = ResolveIP("252.2.2.2");
807  for (unsigned int i = 1; i < 36; i++) {
808  CService addr = ResolveService("250.1.1." + ToString(i));
809  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
810 
811  // No collision yet.
812  BOOST_CHECK(addrman->Good(addr));
813  }
814 
815  // Collision between 36 and 19.
816  CService addr = ResolveService("250.1.1.36");
817  BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
818  BOOST_CHECK(!addrman->Good(addr));
819 
820  auto info = addrman->SelectTriedCollision().first;
821  BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0");
822 
823  // Ensure test of address fails, so that it is evicted.
824  // Update entry in tried by setting last good connection in the deep past.
825  BOOST_CHECK(!addrman->Good(info, /*nTime=*/1));
826  addrman->Attempt(info, /*fCountFailure=*/false, /*nTime=*/GetAdjustedTime() - 61);
827 
828  // Should swap 36 for 19.
829  addrman->ResolveCollisions();
830  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
831  AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
832  BOOST_CHECK(addr_pos.tried);
833 
834  // If 36 was swapped for 19, then adding 36 to tried should fail because we
835  // are attempting to add a duplicate.
836  // We check this by verifying Good() returns false and also verifying that
837  // we have no collisions.
838  BOOST_CHECK(!addrman->Good(addr));
839  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
840 
841  // 19 should fail as a collision (not a duplicate) if we now attempt to move
842  // it to the tried table.
843  CService addr19 = ResolveService("250.1.1.19");
844  BOOST_CHECK(!addrman->Good(addr19));
845  BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.36:0");
846 
847  // Eviction is also successful if too much time has passed since last try
848  SetMockTime(GetTime() + 4 * 60 *60);
849  addrman->ResolveCollisions();
850  BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0");
851  //Now 19 is in tried again, and 36 back to new
852  AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()};
853  BOOST_CHECK(addr_pos19.tried);
854  AddressPosition addr_pos36{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
855  BOOST_CHECK(!addr_pos36.tried);
856 }
857 
858 static CDataStream AddrmanToStream(const AddrMan& addrman)
859 {
860  CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
861  ssPeersIn << Params().MessageStart();
862  ssPeersIn << addrman;
863  return ssPeersIn;
864 }
865 
866 BOOST_AUTO_TEST_CASE(load_addrman)
867 {
869 
870  CService addr1, addr2, addr3;
871  BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
872  BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
873  BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
874  BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false));
875  BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false));
876 
877  // Add three addresses to new table.
879  BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
880  std::vector<CAddress> addresses{CAddress(addr1, NODE_NONE), CAddress(addr2, NODE_NONE), CAddress(addr3, NODE_NONE)};
881  BOOST_CHECK(addrman.Add(addresses, source));
882  BOOST_CHECK(addrman.size() == 3);
883 
884  // Test that the de-serialization does not throw an exception.
885  CDataStream ssPeers1 = AddrmanToStream(addrman);
886  bool exceptionThrown = false;
888 
889  BOOST_CHECK(addrman1.size() == 0);
890  try {
891  unsigned char pchMsgTmp[4];
892  ssPeers1 >> pchMsgTmp;
893  ssPeers1 >> addrman1;
894  } catch (const std::exception&) {
895  exceptionThrown = true;
896  }
897 
898  BOOST_CHECK(addrman1.size() == 3);
899  BOOST_CHECK(exceptionThrown == false);
900 
901  // Test that ReadFromStream creates an addrman with the correct number of addrs.
902  CDataStream ssPeers2 = AddrmanToStream(addrman);
903 
905  BOOST_CHECK(addrman2.size() == 0);
906  ReadFromStream(addrman2, ssPeers2);
907  BOOST_CHECK(addrman2.size() == 3);
908 }
909 
910 // Produce a corrupt peers.dat that claims 20 addrs when it only has one addr.
912 {
914  s << ::Params().MessageStart();
915 
916  unsigned char nVersion = 1;
917  s << nVersion;
918  s << ((unsigned char)32);
919  s << uint256::ONE;
920  s << 10; // nNew
921  s << 10; // nTried
922 
923  int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
924  s << nUBuckets;
925 
926  CService serv;
927  BOOST_CHECK(Lookup("252.1.1.1", serv, 7777, false));
928  CAddress addr = CAddress(serv, NODE_NONE);
929  CNetAddr resolved;
930  BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
931  AddrInfo info = AddrInfo(addr, resolved);
932  s << info;
933 
934  return s;
935 }
936 
937 BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
938 {
939  // Test that the de-serialization of corrupted peers.dat throws an exception.
940  CDataStream ssPeers1 = MakeCorruptPeersDat();
941  bool exceptionThrown = false;
943  BOOST_CHECK(addrman1.size() == 0);
944  try {
945  unsigned char pchMsgTmp[4];
946  ssPeers1 >> pchMsgTmp;
947  ssPeers1 >> addrman1;
948  } catch (const std::exception&) {
949  exceptionThrown = true;
950  }
951  // Even though de-serialization failed addrman is not left in a clean state.
952  BOOST_CHECK(addrman1.size() == 1);
953  BOOST_CHECK(exceptionThrown);
954 
955  // Test that ReadFromStream fails if peers.dat is corrupt
956  CDataStream ssPeers2 = MakeCorruptPeersDat();
957 
959  BOOST_CHECK(addrman2.size() == 0);
960  BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
961 }
962 
963 BOOST_AUTO_TEST_CASE(addrman_update_address)
964 {
965  // Tests updating nTime via Connected() and nServices via SetServices()
966  auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
967  CNetAddr source{ResolveIP("252.2.2.2")};
968  CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
969 
970  int64_t start_time{GetAdjustedTime() - 10000};
971  addr.nTime = start_time;
972  BOOST_CHECK(addrman->Add({addr}, source));
973  BOOST_CHECK_EQUAL(addrman->size(), 1U);
974 
975  // Updating an addrman entry with a different port doesn't change it
976  CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)};
977  addr_diff_port.nTime = start_time;
978  addrman->Connected(addr_diff_port);
979  addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
980  std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
981  BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
982  BOOST_CHECK_EQUAL(vAddr1.at(0).nTime, start_time);
983  BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
984 
985  // Updating an addrman entry with the correct port is successful
986  addrman->Connected(addr);
987  addrman->SetServices(addr, NODE_NETWORK_LIMITED);
988  std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
989  BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
990  BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000);
991  BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
992 }
993 
CService
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:528
LookupHost
bool LookupHost(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition: netbase.cpp:170
ToString
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:87
SER_DISK
@ SER_DISK
Definition: serialize.h:132
asmap.h
addrman_impl.h
setup_common.h
CDataStream::data
value_type * data()
Definition: streams.h:243
string.h
CNetAddr
Network address.
Definition: netaddress.h:118
source
const char * source
Definition: rpcconsole.cpp:66
ResolveService
static CService ResolveService(const std::string &ip, uint16_t port=0)
Definition: addrman_tests.cpp:41
node::NodeContext
NodeContext struct containing references to chain state and connection state.
Definition: context.h:40
m_node
node::NodeContext m_node
Definition: bitcoin-gui.cpp:36
BOOST_AUTO_TEST_CASE
BOOST_AUTO_TEST_CASE(addrman_simple)
Definition: addrman_tests.cpp:63
AddrMan
Stochastic address manager.
Definition: addrman.h:79
GetTime
int64_t GetTime()
DEPRECATED Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable)
Definition: time.cpp:26
AddressPosition::multiplicity
const int multiplicity
Definition: addrman.h:33
clientversion.h
MakeCorruptPeersDat
static CDataStream MakeCorruptPeersDat()
Definition: addrman_tests.cpp:911
AddrInfo
Extended statistics about a CAddress.
Definition: addrman_impl.h:37
NODE_NETWORK_LIMITED
@ NODE_NETWORK_LIMITED
Definition: protocol.h:291
chainparams.h
BOOST_FIXTURE_TEST_SUITE
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
CAddress::nTime
uint32_t nTime
Always included in serialization.
Definition: protocol.h:440
BOOST_AUTO_TEST_SUITE_END
BOOST_AUTO_TEST_SUITE_END()
addrdb.h
random.h
ip
static CService ip(uint32_t i)
Definition: denialofservice_tests.cpp:30
EMPTY_ASMAP
static const std::vector< bool > EMPTY_ASMAP
Definition: addrman_tests.cpp:26
SetMockTime
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:101
BasicTestingSetup
Basic testing setup.
Definition: setup_common.h:83
AddrInfo::GetNewBucket
int GetNewBucket(const uint256 &nKey, const CNetAddr &src, const std::vector< bool > &asmap) const
Calculate in which "new" bucket this entry belongs, given a certain source.
Definition: addrman.cpp:53
uint256
256-bit opaque blob.
Definition: uint256.h:126
addr1
static const std::string addr1
Definition: key_tests.cpp:24
AddressPosition
Test-only struct, capturing info about an address in AddrMan.
Definition: addrman.h:26
CDataStream::size
size_type size() const
Definition: streams.h:236
AddressPosition::position
const int position
Definition: addrman.h:40
NODE_NONE
@ NODE_NONE
Definition: protocol.h:274
CChainParams::MessageStart
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:83
GetCheckRatio
static int32_t GetCheckRatio(const NodeContext &node_ctx)
Definition: addrman_tests.cpp:29
node::NodeContext::args
ArgsManager * args
Definition: context.h:50
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
GetAdjustedTime
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
CAddress
A CService with information about it as peer.
Definition: protocol.h:358
addr2
static const std::string addr2
Definition: key_tests.cpp:25
FromBytes
static std::vector< bool > FromBytes(const unsigned char *source, int vector_size)
Definition: addrman_tests.cpp:49
CLIENT_VERSION
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
CHashWriter
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
ADDRMAN_NEW_BUCKET_COUNT
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman_impl.h:29
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:561
ResolveIP
static CNetAddr ResolveIP(const std::string &ip)
Definition: addrman_tests.cpp:34
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:184
addrman.h
ReadFromStream
void ReadFromStream(AddrMan &addr, CDataStream &ssPeers)
Only used by tests.
Definition: addrdb.cpp:180
SER_NETWORK
@ SER_NETWORK
Definition: serialize.h:131
BOOST_CHECK_THROW
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition: object.cpp:19
AddrInfo::GetTriedBucket
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:46
AddressPosition::bucket
const int bucket
Definition: addrman.h:39
netbase.h
Lookup
bool Lookup(const std::string &name, std::vector< CService > &vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition: netbase.cpp:198
AddrmanToStream
static CDataStream AddrmanToStream(const AddrMan &addrman)
Definition: addrman_tests.cpp:858
CDataStream::str
std::string str() const
Definition: streams.h:223
ArgsManager::GetIntArg
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:594
SER_GETHASH
@ SER_GETHASH
Definition: serialize.h:133
BOOST_CHECK
#define BOOST_CHECK(expr)
Definition: object.cpp:17
BOOST_CHECK_EQUAL
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
DETERMINISTIC
static const bool DETERMINISTIC
Definition: addrman_tests.cpp:27
PROTOCOL_VERSION
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
CService::GetKey
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:1026
uint256::ONE
static const uint256 ONE
Definition: uint256.h:132