PIVX Core  5.6.99
P2P Digital Currency
addrman_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2012-2015 The Bitcoin Core developers
2 // Copyright (c) 2019-2021 The PIVX Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "test/test_pivx.h"
7 #include "test/data/asmap.raw.h"
8 
9 #include "addrman.h"
10 #include "crypto/common.h" // for ReadLE64
11 #include "hash.h"
12 #include "netbase.h"
13 #include "optional.h"
14 #include "util/asmap.h"
15 #include "random.h"
16 
17 #include <string>
18 
19 #include <boost/test/unit_test.hpp>
20 
21 class CAddrManTest : public CAddrMan
22 {
23 private:
25 public:
26  explicit CAddrManTest(bool makeDeterministic = true,
27  std::vector<bool> asmap = std::vector<bool>())
28  {
29  if (makeDeterministic) {
30  // Set addrman addr placement to be deterministic.
32  }
33  deterministic = makeDeterministic;
34  m_asmap = asmap;
35  }
36 
39  {
40  nKey.SetNull();
42  }
43 
44  CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
45  {
46  LOCK(cs);
47  return CAddrMan::Find(addr, pnId);
48  }
49 
50  CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
51  {
52  LOCK(cs);
53  return CAddrMan::Create(addr, addrSource, pnId);
54  }
55 
56  void Delete(int nId)
57  {
58  LOCK(cs);
59  CAddrMan::Delete(nId);
60  }
61 
62  // Used to test deserialization
63  std::pair<int, int> GetBucketAndEntry(const CAddress& addr)
64  {
65  LOCK(cs);
66  int nId = mapAddr[addr];
67  for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
68  for (int entry = 0; entry < ADDRMAN_BUCKET_SIZE; ++entry) {
69  if (nId == vvNew[bucket][entry]) {
70  return std::pair<int, int>(bucket, entry);
71  }
72  }
73  }
74  return std::pair<int, int>(-1, -1);
75  }
76 
77  // Simulates connection failure so that we can test eviction of offline nodes
78  void SimConnFail(CService& addr)
79  {
80  LOCK(cs);
81  int64_t nLastSuccess = 1;
82  Good_(addr, true, nLastSuccess); // Set last good connection in the deep past.
83 
84  bool count_failure = false;
85  int64_t nLastTry = GetAdjustedTime()-61;
86  Attempt(addr, count_failure, nLastTry);
87  }
88 
89  void Clear()
90  {
92  if (deterministic) {
93  nKey.SetNull();
95  }
96  }
97 
98 };
99 
100 static CNetAddr ResolveIP(const std::string& ip)
101 {
102  CNetAddr addr;
103  BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip));
104  return addr;
105 }
106 
107 static CService ResolveService(const std::string& ip, const int port = 0)
108 {
109  CService serv;
110  BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
111  return serv;
112 }
113 
114 
115 static std::vector<bool> FromBytes(const unsigned char* source, int vector_size) {
116  std::vector<bool> result(vector_size);
117  for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) {
118  unsigned char cur_byte = source[byte_i];
119  for (int bit_i = 0; bit_i < 8; ++bit_i) {
120  result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1;
121  }
122  }
123  return result;
124 }
125 
126 
128 
129 BOOST_AUTO_TEST_CASE(addrman_simple)
130 {
131  CAddrManTest addrman;
132 
133  CNetAddr source = ResolveIP("252.2.2.2");
134 
135  // Test 1: Does Addrman respond correctly when empty.
136  BOOST_CHECK(addrman.size() == 0);
137  CAddrInfo addr_null = addrman.Select();
138  BOOST_CHECK(addr_null.ToString() == "[::]:0");
139 
140  // Test 2: Does Addrman::Add work as expected.
141  CService addr1 = ResolveService("250.1.1.1", 8333);
142  addrman.Add(CAddress(addr1, NODE_NONE), source);
143  BOOST_CHECK(addrman.size() == 1);
144  CAddrInfo addr_ret1 = addrman.Select();
145  BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333");
146 
147  // Test 3: Does IP address deduplication work correctly.
148  // Expected dup IP should not be added.
149  CService addr1_dup = ResolveService("250.1.1.1", 8333);
150  addrman.Add(CAddress(addr1_dup, NODE_NONE), source);
151  BOOST_CHECK(addrman.size() == 1);
152 
153 
154  // Test 5: New table has one addr and we add a diff addr we should
155  // have at least one addr.
156  // Note that addrman's size cannot be tested reliably after insertion, as
157  // hash collisions may occur. But we can always be sure of at least one
158  // success.
159  CService addr2 = ResolveService("250.1.1.2", 8333);
160  addrman.Add(CAddress(addr2, NODE_NONE), source);
161  BOOST_CHECK(addrman.size() >= 1);
162 
163  // Test 6: AddrMan::Clear() should empty the new table.
164  addrman.Clear();
165  BOOST_CHECK(addrman.size() == 0);
166  CAddrInfo addr_null2 = addrman.Select();
167  BOOST_CHECK(addr_null2.ToString() == "[::]:0");
168 }
169 
170 BOOST_AUTO_TEST_CASE(addrman_ports)
171 {
172  CAddrManTest addrman;
173 
174  CNetAddr source = ResolveIP("252.2.2.2");
175 
176  BOOST_CHECK(addrman.size() == 0);
177 
178  // Test 7; Addr with same IP but diff port does not replace existing addr.
179  CService addr1 = ResolveService("250.1.1.1", 8333);
180  addrman.Add(CAddress(addr1, NODE_NONE), source);
181  BOOST_CHECK(addrman.size() == 1);
182 
183  CService addr1_port = ResolveService("250.1.1.1", 8334);
184  addrman.Add(CAddress(addr1_port, NODE_NONE), source);
185  BOOST_CHECK(addrman.size() == 1);
186  CAddrInfo addr_ret2 = addrman.Select();
187  BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333");
188 
189  // Test 8: Add same IP but diff port to tried table, it doesn't get added.
190  // Perhaps this is not ideal behavior but it is the current behavior.
191  addrman.Good(CAddress(addr1_port, NODE_NONE));
192  BOOST_CHECK(addrman.size() == 1);
193  bool newOnly = true;
194  CAddrInfo addr_ret3 = addrman.Select(newOnly);
195  BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333");
196 }
197 
198 
199 BOOST_AUTO_TEST_CASE(addrman_select)
200 {
201  CAddrManTest addrman;
202 
203  CNetAddr source = ResolveIP("252.2.2.2");
204 
205  // Test 9: Select from new with 1 addr in new.
206  CService addr1 = ResolveService("250.1.1.1", 8333);
207  addrman.Add(CAddress(addr1, NODE_NONE), source);
208  BOOST_CHECK(addrman.size() == 1);
209 
210  bool newOnly = true;
211  CAddrInfo addr_ret1 = addrman.Select(newOnly);
212  BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333");
213 
214  // Test 10: move addr to tried, select from new expected nothing returned.
215  addrman.Good(CAddress(addr1, NODE_NONE));
216  BOOST_CHECK(addrman.size() == 1);
217  CAddrInfo addr_ret2 = addrman.Select(newOnly);
218  BOOST_CHECK(addr_ret2.ToString() == "[::]:0");
219 
220  CAddrInfo addr_ret3 = addrman.Select();
221  BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333");
222 
223  BOOST_CHECK(addrman.size() == 1);
224 
225 
226  // Add three addresses to new table.
227  CService addr2 = ResolveService("250.3.1.1", 8333);
228  CService addr3 = ResolveService("250.3.2.2", 9999);
229  CService addr4 = ResolveService("250.3.3.3", 9999);
230 
231  addrman.Add(CAddress(addr2, NODE_NONE), ResolveService("250.3.1.1", 8333));
232  addrman.Add(CAddress(addr3, NODE_NONE), ResolveService("250.3.1.1", 8333));
233  addrman.Add(CAddress(addr4, NODE_NONE), ResolveService("250.4.1.1", 8333));
234 
235  // Add three addresses to tried table.
236  CService addr5 = ResolveService("250.4.4.4", 8333);
237  CService addr6 = ResolveService("250.4.5.5", 7777);
238  CService addr7 = ResolveService("250.4.6.6", 8333);
239 
240  addrman.Add(CAddress(addr5, NODE_NONE), ResolveService("250.3.1.1", 8333));
241  addrman.Good(CAddress(addr5, NODE_NONE));
242  addrman.Add(CAddress(addr6, NODE_NONE), ResolveService("250.3.1.1", 8333));
243  addrman.Good(CAddress(addr6, NODE_NONE));
244  addrman.Add(CAddress(addr7, NODE_NONE), ResolveService("250.1.1.3", 8333));
245  addrman.Good(CAddress(addr7, NODE_NONE));
246 
247  // Test 11: 6 addrs + 1 addr from last test = 7.
248  BOOST_CHECK(addrman.size() == 7);
249 
250  // Test 12: Select pulls from new and tried regardless of port number.
251  std::set<uint16_t> ports;
252  for (int i = 0; i < 20; ++i) {
253  ports.insert(addrman.Select().GetPort());
254  }
255  BOOST_CHECK_EQUAL(ports.size(), 3);
256 }
257 
258 BOOST_AUTO_TEST_CASE(addrman_new_collisions)
259 {
260  CAddrManTest addrman;
261 
262  CNetAddr source = ResolveIP("252.2.2.2");
263 
264  BOOST_CHECK(addrman.size() == 0);
265 
266  for (unsigned int i = 1; i < 18; i++) {
267  CService addr = ResolveService("250.1.1." + std::to_string(i));
268  addrman.Add(CAddress(addr, NODE_NONE), source);
269 
270  //Test 13: No collision in new table yet.
271  BOOST_CHECK(addrman.size() == i);
272  }
273 
274  //Test 14: new table collision!
275  CService addr1 = ResolveService("250.1.1.18");
276  addrman.Add(CAddress(addr1, NODE_NONE), source);
277  BOOST_CHECK(addrman.size() == 17);
278 
279  CService addr2 = ResolveService("250.1.1.19");
280  addrman.Add(CAddress(addr2, NODE_NONE), source);
281  BOOST_CHECK(addrman.size() == 18);
282 }
283 
284 BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
285 {
286  CAddrManTest addrman;
287 
288  CNetAddr source = ResolveIP("252.2.2.2");
289 
290  BOOST_CHECK(addrman.size() == 0);
291 
292  for (unsigned int i = 1; i < 80; i++) {
293  CService addr = ResolveService("250.1.1." + std::to_string(i));
294  addrman.Add(CAddress(addr, NODE_NONE), source);
295  addrman.Good(CAddress(addr, NODE_NONE));
296 
297  //Test 15: No collision in tried table yet.
298  BOOST_TEST_MESSAGE(addrman.size());
299  BOOST_CHECK(addrman.size() == i);
300  }
301 
302  //Test 16: tried table collision!
303  CService addr1 = ResolveService("250.1.1.80");
304  addrman.Add(CAddress(addr1, NODE_NONE), source);
305  BOOST_CHECK(addrman.size() == 79);
306 
307  CService addr2 = ResolveService("250.1.1.81");
308  addrman.Add(CAddress(addr2, NODE_NONE), source);
309  BOOST_CHECK(addrman.size() == 80);
310 }
311 
312 BOOST_AUTO_TEST_CASE(addrman_find)
313 {
314  CAddrManTest addrman;
315 
316  BOOST_CHECK_EQUAL(addrman.size(), 0);
317 
318  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
319  CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
320  CAddress addr3 = CAddress(ResolveService("251.255.2.1", 8333), NODE_NONE);
321 
322  CNetAddr source1 = ResolveIP("250.1.2.1");
323  CNetAddr source2 = ResolveIP("250.1.2.2");
324 
325  addrman.Add(addr1, source1);
326  addrman.Add(addr2, source2);
327  addrman.Add(addr3, source1);
328 
329  // Test 17: ensure Find returns an IP matching what we searched on.
330  CAddrInfo* info1 = addrman.Find(addr1);
331  BOOST_CHECK(info1);
332  if (info1)
333  BOOST_CHECK(info1->ToString() == "250.1.2.1:8333");
334 
335  // Test 18; Find does not discriminate by port number.
336  CAddrInfo* info2 = addrman.Find(addr2);
337  BOOST_CHECK(info2);
338  if (info2)
339  BOOST_CHECK(info2->ToString() == info1->ToString());
340 
341  // Test 19: Find returns another IP matching what we searched on.
342  CAddrInfo* info3 = addrman.Find(addr3);
343  BOOST_CHECK(info3);
344  if (info3)
345  BOOST_CHECK(info3->ToString() == "251.255.2.1:8333");
346 }
347 
348 BOOST_AUTO_TEST_CASE(addrman_create)
349 {
350  CAddrManTest addrman;
351 
352  BOOST_CHECK_EQUAL(addrman.size(), 0);
353 
354  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
355  CNetAddr source1 = ResolveIP("250.1.2.1");
356 
357  int nId;
358  CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId);
359 
360  // Test 20: The result should be the same as the input addr.
361  BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333");
362 
363  CAddrInfo* info2 = addrman.Find(addr1);
364  BOOST_CHECK(info2->ToString() == "250.1.2.1:8333");
365 }
366 
367 
368 BOOST_AUTO_TEST_CASE(addrman_delete)
369 {
370  CAddrManTest addrman;
371 
372  BOOST_CHECK_EQUAL(addrman.size(), 0);
373 
374  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
375  CNetAddr source1 = ResolveIP("250.1.2.1");
376 
377  int nId;
378  addrman.Create(addr1, source1, &nId);
379 
380  // Test 21: Delete should actually delete the addr.
381  BOOST_CHECK(addrman.size() == 1);
382  addrman.Delete(nId);
383  BOOST_CHECK(addrman.size() == 0);
384  CAddrInfo* info2 = addrman.Find(addr1);
385  BOOST_CHECK(info2 == nullptr);
386 }
387 
388 BOOST_AUTO_TEST_CASE(addrman_getaddr)
389 {
390  CAddrManTest addrman;
391 
392  // Test: Sanity check, GetAddr should never return anything if addrman
393  // is empty.
394  BOOST_CHECK(addrman.size() == 0);
395  std::vector<CAddress> vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */0, /* network */ nullopt);
396  BOOST_CHECK(vAddr1.size() == 0);
397 
398  CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
399  addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
400  CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
401  addr2.nTime = GetAdjustedTime();
402  CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
403  addr3.nTime = GetAdjustedTime();
404  CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
405  addr4.nTime = GetAdjustedTime();
406  CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
407  addr5.nTime = GetAdjustedTime();
408  CNetAddr source1 = ResolveIP("250.1.2.1");
409  CNetAddr source2 = ResolveIP("250.2.3.3");
410 
411  // Test 23: Ensure GetAddr works with new addresses.
412  addrman.Add(addr1, source1);
413  addrman.Add(addr2, source2);
414  addrman.Add(addr3, source1);
415  addrman.Add(addr4, source2);
416  addrman.Add(addr5, source1);
417 
418  BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ nullopt).size(), 5U);
419  // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
420  BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ nullopt).size(), 1U);
421 
422  // Test 24: Ensure GetAddr works with new and tried addresses.
423  addrman.Good(CAddress(addr1, NODE_NONE));
424  addrman.Good(CAddress(addr2, NODE_NONE));
425  BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ nullopt).size(), 5U);
426  BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ nullopt).size(), 1U);
427 
428  // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs.
429  for (unsigned int i = 1; i < (8 * 256); i++) {
430  int octet1 = i % 256;
431  int octet2 = (i / 256) % 256;
432  int octet3 = (i / (256 * 2)) % 256;
433  std::string strAddr = std::to_string(octet1) + "." + std::to_string(octet2) + "." + std::to_string(octet3) + ".23";
434  CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
435 
436  // Ensure that for all addrs in addrman, isTerrible == false.
437  addr.nTime = GetAdjustedTime();
438  addrman.Add(addr, ResolveIP(strAddr));
439  if (i % 8 == 0)
440  addrman.Good(addr);
441  }
442  std::vector<CAddress> vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ nullopt);
443 
444  size_t percent23 = (addrman.size() * 23) / 100;
445  BOOST_CHECK(vAddr.size() == percent23);
446  BOOST_CHECK(vAddr.size() == 461);
447  // (Addrman.size() < number of addresses added) due to address collisions.
448  BOOST_CHECK(addrman.size() == 2007);
449 }
450 
451 
452 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
453 {
454  CAddrManTest addrman;
455 
456  CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
457  CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
458 
459  CNetAddr source1 = ResolveIP("250.1.1.1");
460 
461 
462  CAddrInfo info1 = CAddrInfo(addr1, source1);
463 
464  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
465  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
466 
467  std::vector<bool> asmap; // use /16
468 
469  BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40);
470 
471  // Test 26: Make sure key actually randomizes bucket placement. A fail on
472  // this test could be a security issue.
473  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
474 
475  // Test 27: Two addresses with same IP but different ports can map to
476  // different buckets because they have different keys.
477  CAddrInfo info2 = CAddrInfo(addr2, source1);
478 
479  BOOST_CHECK(info1.GetKey() != info2.GetKey());
480  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
481 
482  std::set<int> buckets;
483  for (int i = 0; i < 255; i++) {
484  CAddrInfo infoi = CAddrInfo(
485  CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE),
486  ResolveIP("250.1.1." + std::to_string(i)));
487  int bucket = infoi.GetTriedBucket(nKey1, asmap);
488  buckets.insert(bucket);
489  }
490  // Test: IP addresses in the same /16 prefix should
491  // never get more than 8 buckets with legacy grouping
492  BOOST_CHECK_EQUAL(buckets.size(), 8U);
493 
494  buckets.clear();
495  for (int j = 0; j < 255; j++) {
496  CAddrInfo infoj = CAddrInfo(
497  CAddress(ResolveService("250." + std::to_string(j) + ".1.1"), NODE_NONE),
498  ResolveIP("250." + std::to_string(j) + ".1.1"));
499  int bucket = infoj.GetTriedBucket(nKey1, asmap);
500  buckets.insert(bucket);
501  }
502  // Test: IP addresses in the different /16 prefix should map to more than
503  // 8 buckets with legacy grouping
504  BOOST_CHECK_EQUAL(buckets.size(), 160U);
505 }
506 
507 BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
508 {
509  CAddrManTest addrman;
510 
511  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
512  CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
513 
514  CNetAddr source1 = ResolveIP("250.1.2.1");
515 
516  CAddrInfo info1 = CAddrInfo(addr1, source1);
517 
518  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
519  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
520 
521  std::vector<bool> asmap; // use /16
522 
523  // Test: Make sure the buckets are what we expect
524  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786);
525  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786);
526 
527  // Test 30: Make sure key actually randomizes bucket placement. A fail on
528  // this test could be a security issue.
529  BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
530 
531  // Test 31: Ports should not effect bucket placement in the addr
532  CAddrInfo info2 = CAddrInfo(addr2, source1);
533  BOOST_CHECK(info1.GetKey() != info2.GetKey());
534  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
535 
536  std::set<int> buckets;
537  for (int i = 0; i < 255; i++) {
538  CAddrInfo infoi = CAddrInfo(
539  CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE),
540  ResolveIP("250.1.1." + std::to_string(i)));
541  int bucket = infoi.GetNewBucket(nKey1, asmap);
542  buckets.insert(bucket);
543  }
544  // Test 32: IP addresses in the same group (\16 prefix for IPv4) should
545  // always map to the same bucket.
546  BOOST_CHECK(buckets.size() == 1);
547 
548  buckets.clear();
549  for (int j = 0; j < 4 * 255; j++) {
550  CAddrInfo infoj = CAddrInfo(CAddress(
551  ResolveService(
552  std::to_string(250 + (j / 255)) + "." + std::to_string(j % 256) + ".1.1"), NODE_NONE),
553  ResolveIP("251.4.1.1"));
554  int bucket = infoj.GetNewBucket(nKey1, asmap);
555  buckets.insert(bucket);
556  }
557  // Test: IP addresses in the same source groups should map to NO MORE
558  // than 64 buckets.
559  BOOST_CHECK(buckets.size() <= 64);
560 
561  buckets.clear();
562  for (int p = 0; p < 255; p++) {
563  CAddrInfo infoj = CAddrInfo(
564  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
565  ResolveIP("250." + std::to_string(p) + ".1.1"));
566  int bucket = infoj.GetNewBucket(nKey1, asmap);
567  buckets.insert(bucket);
568  }
569  // Test: IP addresses in the different source groups should map to MORE
570  // than 64 buckets.
571  BOOST_CHECK(buckets.size() > 64);
572 }
573 
574 // The following three test cases use asmap.raw
575 // We use an artificial minimal mock mapping
576 // 250.0.0.0/8 AS1000
577 // 101.1.0.0/16 AS1
578 // 101.2.0.0/16 AS2
579 // 101.3.0.0/16 AS3
580 // 101.4.0.0/16 AS4
581 // 101.5.0.0/16 AS5
582 // 101.6.0.0/16 AS6
583 // 101.7.0.0/16 AS7
584 // 101.8.0.0/16 AS8
585 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
586 {
587  CAddrManTest addrman;
588 
589  CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
590  CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
591 
592  CNetAddr source1 = ResolveIP("250.1.1.1");
593 
594 
595  CAddrInfo info1 = CAddrInfo(addr1, source1);
596 
597  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
598  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
599 
600  std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
601 
602  BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236);
603 
604  // Test: Make sure key actually randomizes bucket placement. A fail on
605  // this test could be a security issue.
606  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
607 
608  // Test: Two addresses with same IP but different ports can map to
609  // different buckets because they have different keys.
610  CAddrInfo info2 = CAddrInfo(addr2, source1);
611 
612  BOOST_CHECK(info1.GetKey() != info2.GetKey());
613  BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
614 
615  std::set<int> buckets;
616  for (int j = 0; j < 255; j++) {
617  CAddrInfo infoj = CAddrInfo(
618  CAddress(ResolveService("101." + std::to_string(j) + ".1.1"), NODE_NONE),
619  ResolveIP("101." + std::to_string(j) + ".1.1"));
620  int bucket = infoj.GetTriedBucket(nKey1, asmap);
621  buckets.insert(bucket);
622  }
623  // Test: IP addresses in the different /16 prefix MAY map to more than
624  // 8 buckets.
625  BOOST_CHECK(buckets.size() > 8);
626 
627  buckets.clear();
628  for (int j = 0; j < 255; j++) {
629  CAddrInfo infoj = CAddrInfo(
630  CAddress(ResolveService("250." + std::to_string(j) + ".1.1"), NODE_NONE),
631  ResolveIP("250." + std::to_string(j) + ".1.1"));
632  int bucket = infoj.GetTriedBucket(nKey1, asmap);
633  buckets.insert(bucket);
634  }
635  // Test: IP addresses in the different /16 prefix MAY NOT map to more than
636  // 8 buckets.
637  BOOST_CHECK(buckets.size() == 8);
638 }
639 
640 BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
641 {
642  CAddrManTest addrman;
643 
644  CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
645  CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
646 
647  CNetAddr source1 = ResolveIP("250.1.2.1");
648 
649  CAddrInfo info1 = CAddrInfo(addr1, source1);
650 
651  uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
652  uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
653 
654  std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
655 
656  // Test: Make sure the buckets are what we expect
657  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795);
658  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795);
659 
660  // Test: Make sure key actually randomizes bucket placement. A fail on
661  // this test could be a security issue.
662  BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
663 
664  // Test: Ports should not affect bucket placement in the addr
665  CAddrInfo info2 = CAddrInfo(addr2, source1);
666  BOOST_CHECK(info1.GetKey() != info2.GetKey());
667  BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
668 
669  std::set<int> buckets;
670  for (int i = 0; i < 255; i++) {
671  CAddrInfo infoi = CAddrInfo(
672  CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE),
673  ResolveIP("250.1.1." + std::to_string(i)));
674  int bucket = infoi.GetNewBucket(nKey1, asmap);
675  buckets.insert(bucket);
676  }
677  // Test: IP addresses in the same /16 prefix
678  // usually map to the same bucket.
679  BOOST_CHECK_EQUAL(buckets.size(), 1U);
680 
681  buckets.clear();
682  for (int j = 0; j < 4 * 255; j++) {
683  CAddrInfo infoj = CAddrInfo(CAddress(
684  ResolveService(
685  std::to_string(250 + (j / 255)) + "." + std::to_string(j % 256) + ".1.1"), NODE_NONE),
686  ResolveIP("251.4.1.1"));
687  int bucket = infoj.GetNewBucket(nKey1, asmap);
688  buckets.insert(bucket);
689  }
690  // Test: IP addresses in the same source /16 prefix should not map to more
691  // than 64 buckets.
692  BOOST_CHECK(buckets.size() <= 64);
693 
694  buckets.clear();
695  for (int p = 0; p < 255; p++) {
696  CAddrInfo infoj = CAddrInfo(
697  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
698  ResolveIP("101." + std::to_string(p) + ".1.1"));
699  int bucket = infoj.GetNewBucket(nKey1, asmap);
700  buckets.insert(bucket);
701  }
702  // Test: IP addresses in the different source /16 prefixes usually map to MORE
703  // than 1 bucket.
704  BOOST_CHECK(buckets.size() > 1);
705 
706  buckets.clear();
707  for (int p = 0; p < 255; p++) {
708  CAddrInfo infoj = CAddrInfo(
709  CAddress(ResolveService("250.1.1.1"), NODE_NONE),
710  ResolveIP("250." + std::to_string(p) + ".1.1"));
711  int bucket = infoj.GetNewBucket(nKey1, asmap);
712  buckets.insert(bucket);
713  }
714  // Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
715  // than 1 bucket.
716  BOOST_CHECK(buckets.size() == 1);
717 
718 }
719 
720 BOOST_AUTO_TEST_CASE(addrman_serialization)
721 {
722  std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
723 
724  CAddrManTest addrman_asmap1(true, asmap1);
725  CAddrManTest addrman_asmap1_dup(true, asmap1);
726  CAddrManTest addrman_noasmap;
727  CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
728 
729  CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
730  CNetAddr default_source;
731 
732 
733  addrman_asmap1.Add(addr, default_source);
734 
735  stream << addrman_asmap1;
736  // serizalizing/deserializing addrman with the same asmap
737  stream >> addrman_asmap1_dup;
738 
739  std::pair<int, int> bucketAndEntry_asmap1 = addrman_asmap1.GetBucketAndEntry(addr);
740  std::pair<int, int> bucketAndEntry_asmap1_dup = addrman_asmap1_dup.GetBucketAndEntry(addr);
741  BOOST_CHECK(bucketAndEntry_asmap1.second != -1);
742  BOOST_CHECK(bucketAndEntry_asmap1_dup.second != -1);
743 
744  BOOST_CHECK(bucketAndEntry_asmap1.first == bucketAndEntry_asmap1_dup.first);
745  BOOST_CHECK(bucketAndEntry_asmap1.second == bucketAndEntry_asmap1_dup.second);
746 
747  // deserializing asmaped peers.dat to non-asmaped addrman
748  stream << addrman_asmap1;
749  stream >> addrman_noasmap;
750  std::pair<int, int> bucketAndEntry_noasmap = addrman_noasmap.GetBucketAndEntry(addr);
751  BOOST_CHECK(bucketAndEntry_noasmap.second != -1);
752  BOOST_CHECK(bucketAndEntry_asmap1.first != bucketAndEntry_noasmap.first);
753  BOOST_CHECK(bucketAndEntry_asmap1.second != bucketAndEntry_noasmap.second);
754 
755  // deserializing non-asmaped peers.dat to asmaped addrman
756  addrman_asmap1.Clear();
757  addrman_noasmap.Clear();
758  addrman_noasmap.Add(addr, default_source);
759  stream << addrman_noasmap;
760  stream >> addrman_asmap1;
761  std::pair<int, int> bucketAndEntry_asmap1_deser = addrman_asmap1.GetBucketAndEntry(addr);
762  BOOST_CHECK(bucketAndEntry_asmap1_deser.second != -1);
763  BOOST_CHECK(bucketAndEntry_asmap1_deser.first != bucketAndEntry_noasmap.first);
764  BOOST_CHECK(bucketAndEntry_asmap1_deser.first == bucketAndEntry_asmap1_dup.first);
765  BOOST_CHECK(bucketAndEntry_asmap1_deser.second == bucketAndEntry_asmap1_dup.second);
766 
767  // used to map to different buckets, now maps to the same bucket.
768  addrman_asmap1.Clear();
769  addrman_noasmap.Clear();
770  CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
771  CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
772  addrman_noasmap.Add(addr, default_source);
773  addrman_noasmap.Add(addr2, default_source);
774  std::pair<int, int> bucketAndEntry_noasmap_addr1 = addrman_noasmap.GetBucketAndEntry(addr1);
775  std::pair<int, int> bucketAndEntry_noasmap_addr2 = addrman_noasmap.GetBucketAndEntry(addr2);
776  BOOST_CHECK(bucketAndEntry_noasmap_addr1.first != bucketAndEntry_noasmap_addr2.first);
777  BOOST_CHECK(bucketAndEntry_noasmap_addr1.second != bucketAndEntry_noasmap_addr2.second);
778  stream << addrman_noasmap;
779  stream >> addrman_asmap1;
780  std::pair<int, int> bucketAndEntry_asmap1_deser_addr1 = addrman_asmap1.GetBucketAndEntry(addr1);
781  std::pair<int, int> bucketAndEntry_asmap1_deser_addr2 = addrman_asmap1.GetBucketAndEntry(addr2);
782  BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.first == bucketAndEntry_asmap1_deser_addr2.first);
783  BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.second != bucketAndEntry_asmap1_deser_addr2.second);
784 }
785 
786 
787 BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
788 {
789  CAddrManTest addrman;
790 
791  BOOST_CHECK(addrman.size() == 0);
792 
793  // Empty addrman should return blank addrman info.
794  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
795 
796  // Add twenty two addresses.
797  CNetAddr source = ResolveIP("252.2.2.2");
798  for (unsigned int i = 1; i < 23; i++) {
799  CService addr = ResolveService("250.1.1."+std::to_string(i));
800  addrman.Add(CAddress(addr, NODE_NONE), source);
801  addrman.Good(addr);
802 
803  // No collisions yet.
804  BOOST_CHECK(addrman.size() == i);
805  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
806  }
807 
808  // Ensure Good handles duplicates well.
809  for (unsigned int i = 1; i < 23; i++) {
810  CService addr = ResolveService("250.1.1."+std::to_string(i));
811  addrman.Good(addr);
812 
813  BOOST_CHECK(addrman.size() == 22);
814  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
815  }
816 
817 }
818 
819 BOOST_AUTO_TEST_CASE(addrman_noevict)
820 {
821  CAddrManTest addrman;
822 
823  // Add twenty two addresses.
824  CNetAddr source = ResolveIP("252.2.2.2");
825  for (unsigned int i = 1; i < 23; i++) {
826  CService addr = ResolveService("250.1.1."+std::to_string(i));
827  addrman.Add(CAddress(addr, NODE_NONE), source);
828  addrman.Good(addr);
829 
830  // No collision yet.
831  BOOST_CHECK(addrman.size() == i);
832  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
833  }
834 
835  // Collision between 23 and 19.
836  CService addr23 = ResolveService("250.1.1.23");
837  addrman.Add(CAddress(addr23, NODE_NONE), source);
838  addrman.Good(addr23);
839 
840  BOOST_CHECK(addrman.size() == 23);
841  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.19:0");
842 
843  // 23 should be discarded and 19 not evicted.
844  addrman.ResolveCollisions();
845  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
846 
847  // Lets create two collisions.
848  for (unsigned int i = 24; i < 33; i++) {
849  CService addr = ResolveService("250.1.1."+std::to_string(i));
850  addrman.Add(CAddress(addr, NODE_NONE), source);
851  addrman.Good(addr);
852 
853  BOOST_CHECK(addrman.size() == i);
854  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
855  }
856 
857  // Cause a collision.
858  CService addr33 = ResolveService("250.1.1.33");
859  addrman.Add(CAddress(addr33, NODE_NONE), source);
860  addrman.Good(addr33);
861  BOOST_CHECK(addrman.size() == 33);
862 
863  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.27:0");
864 
865  // Cause a second collision.
866  addrman.Add(CAddress(addr23, NODE_NONE), source);
867  addrman.Good(addr23);
868  BOOST_CHECK(addrman.size() == 33);
869 
870  BOOST_CHECK(addrman.SelectTriedCollision().ToString() != "[::]:0");
871  addrman.ResolveCollisions();
872  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
873 }
874 
875 BOOST_AUTO_TEST_CASE(addrman_evictionworks)
876 {
877  CAddrManTest addrman;
878 
879  BOOST_CHECK(addrman.size() == 0);
880 
881  // Empty addrman should return blank addrman info.
882  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
883 
884  // Add twenty two addresses.
885  CNetAddr source = ResolveIP("252.2.2.2");
886  for (unsigned int i = 1; i < 23; i++) {
887  CService addr = ResolveService("250.1.1."+std::to_string(i));
888  addrman.Add(CAddress(addr, NODE_NONE), source);
889  addrman.Good(addr);
890 
891  // No collision yet.
892  BOOST_CHECK(addrman.size() == i);
893  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
894  }
895 
896  // Collision between 23 and 19.
897  CService addr = ResolveService("250.1.1.23");
898  addrman.Add(CAddress(addr, NODE_NONE), source);
899  addrman.Good(addr);
900 
901  BOOST_CHECK(addrman.size() == 23);
902  CAddrInfo info = addrman.SelectTriedCollision();
903  BOOST_CHECK(info.ToString() == "250.1.1.19:0");
904 
905  // Ensure test of address fails, so that it is evicted.
906  addrman.SimConnFail(info);
907 
908  // Should swap 23 for 19.
909  addrman.ResolveCollisions();
910  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
911 
912  // If 23 was swapped for 19, then this should cause no collisions.
913  addrman.Add(CAddress(addr, NODE_NONE), source);
914  addrman.Good(addr);
915 
916  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
917 
918  // If we insert 19 is should collide with 23.
919  CService addr19 = ResolveService("250.1.1.19");
920  addrman.Add(CAddress(addr19, NODE_NONE), source);
921  addrman.Good(addr19);
922 
923  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "250.1.1.23:0");
924 
925  addrman.ResolveCollisions();
926  BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0");
927 }
928 
929 
CService ip(uint32_t i)
Definition: DoS_tests.cpp:39
#define ADDRMAN_BUCKET_SIZE
Definition: addrman.h:166
#define ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman.h:165
BOOST_AUTO_TEST_CASE(addrman_simple)
Extended statistics about a CAddress.
Definition: addrman.h:37
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:17
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:27
Stochastical (IP) address manager.
Definition: addrman.h:178
bool Add(const CAddress &addr, const CNetAddr &source, int64_t nTimePenalty=0)
Add a single address.
Definition: addrman.h:623
void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs)
Delete an entry. It must not be in tried, and have refcount 0.
Definition: addrman.cpp:124
FastRandomContext insecure_rand
Source of random numbers for randomization in inner loops.
Definition: addrman.h:242
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
find an entry, creating it if necessary.
Definition: addrman.cpp:92
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.h:603
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.h:661
void Clear()
Definition: addrman.h:568
CAddrInfo Select(bool newOnly=false)
Choose an address to connect to.
Definition: addrman.h:695
RecursiveMutex cs
critical section to protect the inner data structures
Definition: addrman.h:182
void ResolveCollisions()
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
Definition: addrman.h:670
CAddrInfo SelectTriedCollision()
Randomly select an address in tried that another address is attempting to evict.
Definition: addrman.h:679
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs)
Find an entry.
Definition: addrman.cpp:79
std::vector< bool > m_asmap
Definition: addrman.h:317
void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs)
Mark an entry "good", possibly moving it from "new" to "tried".
Definition: addrman.cpp:204
void Good(const CService &addr, bool test_before_evict=true, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible.
Definition: addrman.h:652
uint256 nKey
secret key to randomize bucket select with
Definition: addrman.h:239
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, Optional< Network > network)
Return all or many randomly selected addresses, optionally by network.
Definition: addrman.h:714
void SimConnFail(CService &addr)
void MakeDeterministic()
Ensure that bucket placement is always the same for testing purposes.
std::pair< int, int > GetBucketAndEntry(const CAddress &addr)
CAddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr)
CAddrInfo * Find(const CNetAddr &addr, int *pnId=nullptr)
CAddrManTest(bool makeDeterministic=true, std::vector< bool > asmap=std::vector< bool >())
void Delete(int nId)
A CService with information about it as peer.
Definition: protocol.h:338
uint32_t nTime
Always included in serialization, except in the network format on INIT_PROTO_VERSION.
Definition: protocol.h:428
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:216
Network address.
Definition: netaddress.h:120
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:484
std::string ToString() const
Definition: netaddress.cpp:954
uint16_t GetPort() const
Definition: netaddress.cpp:882
std::vector< unsigned char > GetKey() const
Definition: netaddress.cpp:932
Fast randomness source.
Definition: random.h:107
void SetNull()
Definition: uint256.h:44
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
@ LOCK
Definition: lockunlock.h:16
bool Lookup(const std::string &name, std::vector< CService > &vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
Definition: netbase.cpp:177
bool LookupHost(const std::string &name, std::vector< CNetAddr > &vIP, unsigned int nMaxSolutions, bool fAllowLookup)
Definition: netbase.cpp:149
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
#define BOOST_CHECK(expr)
Definition: object.cpp:17
@ NODE_NONE
Definition: protocol.h:314
const char * source
Definition: rpcconsole.cpp:52
@ SER_NETWORK
Definition: serialize.h:174
@ SER_GETHASH
Definition: serialize.h:176
Basic testing setup.
Definition: test_pivx.h:51
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
#define strprintf
Definition: tinyformat.h:1056