Bitcoin Core 22.99.0
P2P Digital Currency
addrman_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2012-2020 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>
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
23using namespace std::literals;
24
26{
27public:
28 virtual void Serialize(CDataStream& s) const = 0;
29
31 : AddrMan(/* asmap */ std::vector<bool>(), /* deterministic */ true, /* consistency_check_ratio */ 100)
32 {}
33};
34
36{
37public:
38 void Serialize(CDataStream& s) const override
39 {
41 }
42};
43
45{
46public:
47 void Serialize(CDataStream& s) const override
48 {
49 // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
50 unsigned char nVersion = 1;
51 s << nVersion;
52 s << ((unsigned char)32);
53 s << uint256::ONE;
54 s << 10; // nNew
55 s << 10; // nTried
56
57 int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
58 s << nUBuckets;
59
60 CService serv;
61 BOOST_CHECK(Lookup("252.1.1.1", serv, 7777, false));
62 CAddress addr = CAddress(serv, NODE_NONE);
63 CNetAddr resolved;
64 BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
65 AddrInfo info = AddrInfo(addr, resolved);
66 s << info;
67 }
68};
69
71{
73 ssPeersIn << Params().MessageStart();
74 ssPeersIn << _addrman;
75 std::string str = ssPeersIn.str();
76 std::vector<unsigned char> vchData(str.begin(), str.end());
77 return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
78}
79
80class AddrManTest : public AddrMan
81{
82private:
84public:
85 explicit AddrManTest(bool makeDeterministic = true,
86 std::vector<bool> asmap = std::vector<bool>())
87 : AddrMan(asmap, makeDeterministic, /* consistency_check_ratio */ 100)
88 {
89 deterministic = makeDeterministic;
90 }
91
92 AddrInfo* Find(const CService& addr, int* pnId = nullptr)
93 {
94 LOCK(m_impl->cs);
95 return m_impl->Find(addr, pnId);
96 }
97
98 AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
99 {
100 LOCK(m_impl->cs);
101 return m_impl->Create(addr, addrSource, pnId);
102 }
103
104 void Delete(int nId)
105 {
106 LOCK(m_impl->cs);
107 m_impl->Delete(nId);
108 }
109
110 // Used to test deserialization
111 std::pair<int, int> GetBucketAndEntry(const CAddress& addr)
112 {
113 LOCK(m_impl->cs);
114 int nId = m_impl->mapAddr[addr];
115 for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) {
116 for (int entry = 0; entry < ADDRMAN_BUCKET_SIZE; ++entry) {
117 if (nId == m_impl->vvNew[bucket][entry]) {
118 return std::pair<int, int>(bucket, entry);
119 }
120 }
121 }
122 return std::pair<int, int>(-1, -1);
123 }
124
125 // Simulates connection failure so that we can test eviction of offline nodes
126 void SimConnFail(const CService& addr)
127 {
128 int64_t nLastSuccess = 1;
129 // Set last good connection in the deep past.
130 Good(addr, nLastSuccess);
131
132 bool count_failure = false;
133 int64_t nLastTry = GetAdjustedTime()-61;
134 Attempt(addr, count_failure, nLastTry);
135 }
136};
137
138static CNetAddr ResolveIP(const std::string& ip)
139{
140 CNetAddr addr;
141 BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip));
142 return addr;
143}
144
145static CService ResolveService(const std::string& ip, uint16_t port = 0)
146{
147 CService serv;
148 BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
149 return serv;
150}
151
152
153static std::vector<bool> FromBytes(const unsigned char* source, int vector_size) {
154 std::vector<bool> result(vector_size);
155 for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) {
156 unsigned char cur_byte = source[byte_i];
157 for (int bit_i = 0; bit_i < 8; ++bit_i) {
158 result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1;
159 }
160 }
161 return result;
162}
163
164
166
167BOOST_AUTO_TEST_CASE(addrman_simple)
168{
169 auto addrman = std::make_unique<AddrManTest>();
170
171 CNetAddr source = ResolveIP("252.2.2.2");
172
173 // Test: Does Addrman respond correctly when empty.
174 BOOST_CHECK_EQUAL(addrman->size(), 0U);
175 auto addr_null = addrman->Select().first;
176 BOOST_CHECK_EQUAL(addr_null.ToString(), "[::]:0");
177
178 // Test: Does Addrman::Add work as expected.
179 CService addr1 = ResolveService("250.1.1.1", 8333);
180 BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
181 BOOST_CHECK_EQUAL(addrman->size(), 1U);
182 auto addr_ret1 = addrman->Select().first;
183 BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
184
185 // Test: Does IP address deduplication work correctly.
186 // Expected dup IP should not be added.
187 CService addr1_dup = ResolveService("250.1.1.1", 8333);
188 BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
189 BOOST_CHECK_EQUAL(addrman->size(), 1U);
190
191
192 // Test: New table has one addr and we add a diff addr we should
193 // have at least one addr.
194 // Note that addrman's size cannot be tested reliably after insertion, as
195 // hash collisions may occur. But we can always be sure of at least one
196 // success.
197
198 CService addr2 = ResolveService("250.1.1.2", 8333);
199 BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
200 BOOST_CHECK(addrman->size() >= 1);
201
202 // Test: reset addrman and test AddrMan::Add multiple addresses works as expected
203 addrman = std::make_unique<AddrManTest>();
204 std::vector<CAddress> vAddr;
205 vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
206 vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
207 BOOST_CHECK(addrman->Add(vAddr, source));
208 BOOST_CHECK(addrman->size() >= 1);
209}
210
212{
213 AddrManTest addrman;
214
215 CNetAddr source = ResolveIP("252.2.2.2");
216
217 BOOST_CHECK_EQUAL(addrman.size(), 0U);
218
219 // Test 7; Addr with same IP but diff port does not replace existing addr.
220 CService addr1 = ResolveService("250.1.1.1", 8333);
221 BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source));
222 BOOST_CHECK_EQUAL(addrman.size(), 1U);
223
224 CService addr1_port = ResolveService("250.1.1.1", 8334);
225 BOOST_CHECK(addrman.Add({CAddress(addr1_port, NODE_NONE)}, source));
226 BOOST_CHECK_EQUAL(addrman.size(), 2U);
227 auto addr_ret2 = addrman.Select().first;
228 BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333" || addr_ret2.ToString() == "250.1.1.1:8334");
229
230 // Test: Add same IP but diff port to tried table; this converts the entry with
231 // the specified port to tried, but not the other.
232 addrman.Good(CAddress(addr1_port, NODE_NONE));
233 BOOST_CHECK_EQUAL(addrman.size(), 2U);
234 bool newOnly = true;
235 auto addr_ret3 = addrman.Select(newOnly).first;
236 BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
237}
238
239
240BOOST_AUTO_TEST_CASE(addrman_select)
241{
242 AddrManTest addrman;
243
244 CNetAddr source = ResolveIP("252.2.2.2");
245
246 // Test: Select from new with 1 addr in new.
247 CService addr1 = ResolveService("250.1.1.1", 8333);
248 BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source));
249 BOOST_CHECK_EQUAL(addrman.size(), 1U);
250
251 bool newOnly = true;
252 auto addr_ret1 = addrman.Select(newOnly).first;
253 BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333");
254
255 // Test: move addr to tried, select from new expected nothing returned.
256 addrman.Good(CAddress(addr1, NODE_NONE));
257 BOOST_CHECK_EQUAL(addrman.size(), 1U);
258 auto addr_ret2 = addrman.Select(newOnly).first;
259 BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0");
260
261 auto addr_ret3 = addrman.Select().first;
262 BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333");
263
264 BOOST_CHECK_EQUAL(addrman.size(), 1U);
265
266
267 // Add three addresses to new table.
268 CService addr2 = ResolveService("250.3.1.1", 8333);
269 CService addr3 = ResolveService("250.3.2.2", 9999);
270 CService addr4 = ResolveService("250.3.3.3", 9999);
271
272 BOOST_CHECK(addrman.Add({CAddress(addr2, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
273 BOOST_CHECK(addrman.Add({CAddress(addr3, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
274 BOOST_CHECK(addrman.Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));
275
276 // Add three addresses to tried table.
277 CService addr5 = ResolveService("250.4.4.4", 8333);
278 CService addr6 = ResolveService("250.4.5.5", 7777);
279 CService addr7 = ResolveService("250.4.6.6", 8333);
280
281 BOOST_CHECK(addrman.Add({CAddress(addr5, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
282 addrman.Good(CAddress(addr5, NODE_NONE));
283 BOOST_CHECK(addrman.Add({CAddress(addr6, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
284 addrman.Good(CAddress(addr6, NODE_NONE));
285 BOOST_CHECK(addrman.Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));
286 addrman.Good(CAddress(addr7, NODE_NONE));
287
288 // Test: 6 addrs + 1 addr from last test = 7.
289 BOOST_CHECK_EQUAL(addrman.size(), 7U);
290
291 // Test: Select pulls from new and tried regardless of port number.
292 std::set<uint16_t> ports;
293 for (int i = 0; i < 20; ++i) {
294 ports.insert(addrman.Select().first.GetPort());
295 }
296 BOOST_CHECK_EQUAL(ports.size(), 3U);
297}
298
299BOOST_AUTO_TEST_CASE(addrman_new_collisions)
300{
301 AddrManTest addrman;
302
303 CNetAddr source = ResolveIP("252.2.2.2");
304
305 uint32_t num_addrs{0};
306
307 BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
308
309 while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1
310 CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
311 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
312
313 //Test: No collision in new table yet.
314 BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
315 }
316
317 //Test: new table collision!
318 CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
319 uint32_t collisions{1};
320 BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source));
321 BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
322
323 CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
324 BOOST_CHECK(addrman.Add({CAddress(addr2, NODE_NONE)}, source));
325 BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
326}
327
328BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
329{
330 AddrManTest addrman;
331
332 CNetAddr source = ResolveIP("252.2.2.2");
333
334 uint32_t num_addrs{0};
335
336 BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
337
338 while (num_addrs < 64) { // Magic number! 250.1.1.1 - 250.1.1.64 do not collide with deterministic key = 1
339 CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
340 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
341 addrman.Good(CAddress(addr, NODE_NONE));
342
343 //Test: No collision in tried table yet.
344 BOOST_CHECK_EQUAL(addrman.size(), num_addrs);
345 }
346
347 //Test: tried table collision!
348 CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
349 uint32_t collisions{1};
350 BOOST_CHECK(!addrman.Add({CAddress(addr1, NODE_NONE)}, source));
351 BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
352
353 CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
354 BOOST_CHECK(addrman.Add({CAddress(addr2, NODE_NONE)}, source));
355 BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions);
356}
357
359{
360 AddrManTest addrman;
361
362 BOOST_CHECK_EQUAL(addrman.size(), 0U);
363
364 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
365 CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
366 CAddress addr3 = CAddress(ResolveService("251.255.2.1", 8333), NODE_NONE);
367
368 CNetAddr source1 = ResolveIP("250.1.2.1");
369 CNetAddr source2 = ResolveIP("250.1.2.2");
370
371 BOOST_CHECK(addrman.Add({addr1}, source1));
372 BOOST_CHECK(addrman.Add({addr2}, source2));
373 BOOST_CHECK(addrman.Add({addr3}, source1));
374
375 // Test: ensure Find returns an IP/port matching what we searched on.
376 AddrInfo* info1 = addrman.Find(addr1);
377 BOOST_REQUIRE(info1);
378 BOOST_CHECK_EQUAL(info1->ToString(), "250.1.2.1:8333");
379
380 // Test; Find discriminates by port number.
381 AddrInfo* info2 = addrman.Find(addr2);
382 BOOST_REQUIRE(info2);
383 BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:9999");
384
385 // Test: Find returns another IP matching what we searched on.
386 AddrInfo* info3 = addrman.Find(addr3);
387 BOOST_REQUIRE(info3);
388 BOOST_CHECK_EQUAL(info3->ToString(), "251.255.2.1:8333");
389}
390
391BOOST_AUTO_TEST_CASE(addrman_create)
392{
393 AddrManTest addrman;
394
395 BOOST_CHECK_EQUAL(addrman.size(), 0U);
396
397 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
398 CNetAddr source1 = ResolveIP("250.1.2.1");
399
400 int nId;
401 AddrInfo* pinfo = addrman.Create(addr1, source1, &nId);
402
403 // Test: The result should be the same as the input addr.
404 BOOST_CHECK_EQUAL(pinfo->ToString(), "250.1.2.1:8333");
405
406 AddrInfo* info2 = addrman.Find(addr1);
407 BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:8333");
408}
409
410
411BOOST_AUTO_TEST_CASE(addrman_delete)
412{
413 AddrManTest addrman;
414
415 BOOST_CHECK_EQUAL(addrman.size(), 0U);
416
417 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
418 CNetAddr source1 = ResolveIP("250.1.2.1");
419
420 int nId;
421 addrman.Create(addr1, source1, &nId);
422
423 // Test: Delete should actually delete the addr.
424 BOOST_CHECK_EQUAL(addrman.size(), 1U);
425 addrman.Delete(nId);
426 BOOST_CHECK_EQUAL(addrman.size(), 0U);
427 AddrInfo* info2 = addrman.Find(addr1);
428 BOOST_CHECK(info2 == nullptr);
429}
430
431BOOST_AUTO_TEST_CASE(addrman_getaddr)
432{
433 AddrManTest addrman;
434
435 // Test: Sanity check, GetAddr should never return anything if addrman
436 // is empty.
437 BOOST_CHECK_EQUAL(addrman.size(), 0U);
438 std::vector<CAddress> vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt);
439 BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
440
441 CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
442 addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
443 CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
444 addr2.nTime = GetAdjustedTime();
445 CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
446 addr3.nTime = GetAdjustedTime();
447 CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
448 addr4.nTime = GetAdjustedTime();
449 CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
450 addr5.nTime = GetAdjustedTime();
451 CNetAddr source1 = ResolveIP("250.1.2.1");
452 CNetAddr source2 = ResolveIP("250.2.3.3");
453
454 // Test: Ensure GetAddr works with new addresses.
455 BOOST_CHECK(addrman.Add({addr1, addr3, addr5}, source1));
456 BOOST_CHECK(addrman.Add({addr2, addr4}, source2));
457
458 BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U);
459 // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
460 BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U);
461
462 // Test: Ensure GetAddr works with new and tried addresses.
463 addrman.Good(CAddress(addr1, NODE_NONE));
464 addrman.Good(CAddress(addr2, NODE_NONE));
465 BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U);
466 BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U);
467
468 // Test: Ensure GetAddr still returns 23% when addrman has many addrs.
469 for (unsigned int i = 1; i < (8 * 256); i++) {
470 int octet1 = i % 256;
471 int octet2 = i >> 8 % 256;
472 std::string strAddr = ToString(octet1) + "." + ToString(octet2) + ".1.23";
473 CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
474
475 // Ensure that for all addrs in addrman, isTerrible == false.
476 addr.nTime = GetAdjustedTime();
477 addrman.Add({addr}, ResolveIP(strAddr));
478 if (i % 8 == 0)
479 addrman.Good(addr);
480 }
481 std::vector<CAddress> vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
482
483 size_t percent23 = (addrman.size() * 23) / 100;
484 BOOST_CHECK_EQUAL(vAddr.size(), percent23);
485 BOOST_CHECK_EQUAL(vAddr.size(), 461U);
486 // (Addrman.size() < number of addresses added) due to address collisions.
487 BOOST_CHECK_EQUAL(addrman.size(), 2006U);
488}
489
490
491BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
492{
493 AddrManTest addrman;
494
495 CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
496 CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
497
498 CNetAddr source1 = ResolveIP("250.1.1.1");
499
500
501 AddrInfo info1 = AddrInfo(addr1, source1);
502
503 uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
504 uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
505
506 std::vector<bool> asmap; // use /16
507
508 BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40);
509
510 // Test: Make sure key actually randomizes bucket placement. A fail on
511 // this test could be a security issue.
512 BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
513
514 // Test: Two addresses with same IP but different ports can map to
515 // different buckets because they have different keys.
516 AddrInfo info2 = AddrInfo(addr2, source1);
517
518 BOOST_CHECK(info1.GetKey() != info2.GetKey());
519 BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
520
521 std::set<int> buckets;
522 for (int i = 0; i < 255; i++) {
523 AddrInfo infoi = AddrInfo(
524 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
525 ResolveIP("250.1.1." + ToString(i)));
526 int bucket = infoi.GetTriedBucket(nKey1, asmap);
527 buckets.insert(bucket);
528 }
529 // Test: IP addresses in the same /16 prefix should
530 // never get more than 8 buckets with legacy grouping
531 BOOST_CHECK_EQUAL(buckets.size(), 8U);
532
533 buckets.clear();
534 for (int j = 0; j < 255; j++) {
535 AddrInfo infoj = AddrInfo(
536 CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
537 ResolveIP("250." + ToString(j) + ".1.1"));
538 int bucket = infoj.GetTriedBucket(nKey1, asmap);
539 buckets.insert(bucket);
540 }
541 // Test: IP addresses in the different /16 prefix should map to more than
542 // 8 buckets with legacy grouping
543 BOOST_CHECK_EQUAL(buckets.size(), 160U);
544}
545
546BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
547{
548 AddrManTest addrman;
549
550 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
551 CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
552
553 CNetAddr source1 = ResolveIP("250.1.2.1");
554
555 AddrInfo info1 = AddrInfo(addr1, source1);
556
557 uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
558 uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
559
560 std::vector<bool> asmap; // use /16
561
562 // Test: Make sure the buckets are what we expect
563 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786);
564 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786);
565
566 // Test: Make sure key actually randomizes bucket placement. A fail on
567 // this test could be a security issue.
568 BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
569
570 // Test: Ports should not affect bucket placement in the addr
571 AddrInfo info2 = AddrInfo(addr2, source1);
572 BOOST_CHECK(info1.GetKey() != info2.GetKey());
573 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
574
575 std::set<int> buckets;
576 for (int i = 0; i < 255; i++) {
577 AddrInfo infoi = AddrInfo(
578 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
579 ResolveIP("250.1.1." + ToString(i)));
580 int bucket = infoi.GetNewBucket(nKey1, asmap);
581 buckets.insert(bucket);
582 }
583 // Test: IP addresses in the same group (\16 prefix for IPv4) should
584 // always map to the same bucket.
585 BOOST_CHECK_EQUAL(buckets.size(), 1U);
586
587 buckets.clear();
588 for (int j = 0; j < 4 * 255; j++) {
589 AddrInfo infoj = AddrInfo(CAddress(
591 ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
592 ResolveIP("251.4.1.1"));
593 int bucket = infoj.GetNewBucket(nKey1, asmap);
594 buckets.insert(bucket);
595 }
596 // Test: IP addresses in the same source groups should map to NO MORE
597 // than 64 buckets.
598 BOOST_CHECK(buckets.size() <= 64);
599
600 buckets.clear();
601 for (int p = 0; p < 255; p++) {
602 AddrInfo infoj = AddrInfo(
603 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
604 ResolveIP("250." + ToString(p) + ".1.1"));
605 int bucket = infoj.GetNewBucket(nKey1, asmap);
606 buckets.insert(bucket);
607 }
608 // Test: IP addresses in the different source groups should map to MORE
609 // than 64 buckets.
610 BOOST_CHECK(buckets.size() > 64);
611}
612
613// The following three test cases use asmap.raw
614// We use an artificial minimal mock mapping
615// 250.0.0.0/8 AS1000
616// 101.1.0.0/16 AS1
617// 101.2.0.0/16 AS2
618// 101.3.0.0/16 AS3
619// 101.4.0.0/16 AS4
620// 101.5.0.0/16 AS5
621// 101.6.0.0/16 AS6
622// 101.7.0.0/16 AS7
623// 101.8.0.0/16 AS8
624BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
625{
626 AddrManTest addrman;
627
628 CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
629 CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
630
631 CNetAddr source1 = ResolveIP("250.1.1.1");
632
633
634 AddrInfo info1 = AddrInfo(addr1, source1);
635
636 uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
637 uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
638
639 std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
640
641 BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236);
642
643 // Test: Make sure key actually randomizes bucket placement. A fail on
644 // this test could be a security issue.
645 BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
646
647 // Test: Two addresses with same IP but different ports can map to
648 // different buckets because they have different keys.
649 AddrInfo info2 = AddrInfo(addr2, source1);
650
651 BOOST_CHECK(info1.GetKey() != info2.GetKey());
652 BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
653
654 std::set<int> buckets;
655 for (int j = 0; j < 255; j++) {
656 AddrInfo infoj = AddrInfo(
657 CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
658 ResolveIP("101." + ToString(j) + ".1.1"));
659 int bucket = infoj.GetTriedBucket(nKey1, asmap);
660 buckets.insert(bucket);
661 }
662 // Test: IP addresses in the different /16 prefix MAY map to more than
663 // 8 buckets.
664 BOOST_CHECK(buckets.size() > 8);
665
666 buckets.clear();
667 for (int j = 0; j < 255; j++) {
668 AddrInfo infoj = AddrInfo(
669 CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
670 ResolveIP("250." + ToString(j) + ".1.1"));
671 int bucket = infoj.GetTriedBucket(nKey1, asmap);
672 buckets.insert(bucket);
673 }
674 // Test: IP addresses in the different /16 prefix MAY NOT map to more than
675 // 8 buckets.
676 BOOST_CHECK(buckets.size() == 8);
677}
678
679BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
680{
681 AddrManTest addrman;
682
683 CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
684 CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
685
686 CNetAddr source1 = ResolveIP("250.1.2.1");
687
688 AddrInfo info1 = AddrInfo(addr1, source1);
689
690 uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
691 uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
692
693 std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
694
695 // Test: Make sure the buckets are what we expect
696 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795);
697 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795);
698
699 // Test: Make sure key actually randomizes bucket placement. A fail on
700 // this test could be a security issue.
701 BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
702
703 // Test: Ports should not affect bucket placement in the addr
704 AddrInfo info2 = AddrInfo(addr2, source1);
705 BOOST_CHECK(info1.GetKey() != info2.GetKey());
706 BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
707
708 std::set<int> buckets;
709 for (int i = 0; i < 255; i++) {
710 AddrInfo infoi = AddrInfo(
711 CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
712 ResolveIP("250.1.1." + ToString(i)));
713 int bucket = infoi.GetNewBucket(nKey1, asmap);
714 buckets.insert(bucket);
715 }
716 // Test: IP addresses in the same /16 prefix
717 // usually map to the same bucket.
718 BOOST_CHECK_EQUAL(buckets.size(), 1U);
719
720 buckets.clear();
721 for (int j = 0; j < 4 * 255; j++) {
722 AddrInfo infoj = AddrInfo(CAddress(
724 ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
725 ResolveIP("251.4.1.1"));
726 int bucket = infoj.GetNewBucket(nKey1, asmap);
727 buckets.insert(bucket);
728 }
729 // Test: IP addresses in the same source /16 prefix should not map to more
730 // than 64 buckets.
731 BOOST_CHECK(buckets.size() <= 64);
732
733 buckets.clear();
734 for (int p = 0; p < 255; p++) {
735 AddrInfo infoj = AddrInfo(
736 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
737 ResolveIP("101." + ToString(p) + ".1.1"));
738 int bucket = infoj.GetNewBucket(nKey1, asmap);
739 buckets.insert(bucket);
740 }
741 // Test: IP addresses in the different source /16 prefixes usually map to MORE
742 // than 1 bucket.
743 BOOST_CHECK(buckets.size() > 1);
744
745 buckets.clear();
746 for (int p = 0; p < 255; p++) {
747 AddrInfo infoj = AddrInfo(
748 CAddress(ResolveService("250.1.1.1"), NODE_NONE),
749 ResolveIP("250." + ToString(p) + ".1.1"));
750 int bucket = infoj.GetNewBucket(nKey1, asmap);
751 buckets.insert(bucket);
752 }
753 // Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
754 // than 1 bucket.
755 BOOST_CHECK(buckets.size() == 1);
756
757}
758
759BOOST_AUTO_TEST_CASE(addrman_serialization)
760{
761 std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
762
763 auto addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
764 auto addrman_asmap1_dup = std::make_unique<AddrManTest>(true, asmap1);
765 auto addrman_noasmap = std::make_unique<AddrManTest>();
767
768 CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
769 CNetAddr default_source;
770
771
772 addrman_asmap1->Add({addr}, default_source);
773
774 stream << *addrman_asmap1;
775 // serizalizing/deserializing addrman with the same asmap
776 stream >> *addrman_asmap1_dup;
777
778 std::pair<int, int> bucketAndEntry_asmap1 = addrman_asmap1->GetBucketAndEntry(addr);
779 std::pair<int, int> bucketAndEntry_asmap1_dup = addrman_asmap1_dup->GetBucketAndEntry(addr);
780 BOOST_CHECK(bucketAndEntry_asmap1.second != -1);
781 BOOST_CHECK(bucketAndEntry_asmap1_dup.second != -1);
782
783 BOOST_CHECK(bucketAndEntry_asmap1.first == bucketAndEntry_asmap1_dup.first);
784 BOOST_CHECK(bucketAndEntry_asmap1.second == bucketAndEntry_asmap1_dup.second);
785
786 // deserializing asmaped peers.dat to non-asmaped addrman
787 stream << *addrman_asmap1;
788 stream >> *addrman_noasmap;
789 std::pair<int, int> bucketAndEntry_noasmap = addrman_noasmap->GetBucketAndEntry(addr);
790 BOOST_CHECK(bucketAndEntry_noasmap.second != -1);
791 BOOST_CHECK(bucketAndEntry_asmap1.first != bucketAndEntry_noasmap.first);
792 BOOST_CHECK(bucketAndEntry_asmap1.second != bucketAndEntry_noasmap.second);
793
794 // deserializing non-asmaped peers.dat to asmaped addrman
795 addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
796 addrman_noasmap = std::make_unique<AddrManTest>();
797 addrman_noasmap->Add({addr}, default_source);
798 stream << *addrman_noasmap;
799 stream >> *addrman_asmap1;
800 std::pair<int, int> bucketAndEntry_asmap1_deser = addrman_asmap1->GetBucketAndEntry(addr);
801 BOOST_CHECK(bucketAndEntry_asmap1_deser.second != -1);
802 BOOST_CHECK(bucketAndEntry_asmap1_deser.first != bucketAndEntry_noasmap.first);
803 BOOST_CHECK(bucketAndEntry_asmap1_deser.first == bucketAndEntry_asmap1_dup.first);
804 BOOST_CHECK(bucketAndEntry_asmap1_deser.second == bucketAndEntry_asmap1_dup.second);
805
806 // used to map to different buckets, now maps to the same bucket.
807 addrman_asmap1 = std::make_unique<AddrManTest>(true, asmap1);
808 addrman_noasmap = std::make_unique<AddrManTest>();
811 addrman_noasmap->Add({addr, addr2}, default_source);
812 std::pair<int, int> bucketAndEntry_noasmap_addr1 = addrman_noasmap->GetBucketAndEntry(addr1);
813 std::pair<int, int> bucketAndEntry_noasmap_addr2 = addrman_noasmap->GetBucketAndEntry(addr2);
814 BOOST_CHECK(bucketAndEntry_noasmap_addr1.first != bucketAndEntry_noasmap_addr2.first);
815 BOOST_CHECK(bucketAndEntry_noasmap_addr1.second != bucketAndEntry_noasmap_addr2.second);
816 stream << *addrman_noasmap;
817 stream >> *addrman_asmap1;
818 std::pair<int, int> bucketAndEntry_asmap1_deser_addr1 = addrman_asmap1->GetBucketAndEntry(addr1);
819 std::pair<int, int> bucketAndEntry_asmap1_deser_addr2 = addrman_asmap1->GetBucketAndEntry(addr2);
820 BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.first == bucketAndEntry_asmap1_deser_addr2.first);
821 BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.second != bucketAndEntry_asmap1_deser_addr2.second);
822}
823
824BOOST_AUTO_TEST_CASE(remove_invalid)
825{
826 // Confirm that invalid addresses are ignored in unserialization.
827
828 auto addrman = std::make_unique<AddrManTest>();
830
831 const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
832 const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
833 const CAddress tried1{ResolveService("7.7.7.7"), NODE_NONE};
834 const CAddress tried2{ResolveService("8.8.8.8"), NODE_NONE};
835
836 addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
837 addrman->Good(tried1);
838 addrman->Good(tried2);
839 BOOST_REQUIRE_EQUAL(addrman->size(), 4);
840
841 stream << *addrman;
842
843 const std::string str{stream.str()};
844 size_t pos;
845
846 const char new2_raw[]{6, 6, 6, 6};
847 const uint8_t new2_raw_replacement[]{0, 0, 0, 0}; // 0.0.0.0 is !IsValid()
848 pos = str.find(new2_raw, 0, sizeof(new2_raw));
849 BOOST_REQUIRE(pos != std::string::npos);
850 BOOST_REQUIRE(pos + sizeof(new2_raw_replacement) <= stream.size());
851 memcpy(stream.data() + pos, new2_raw_replacement, sizeof(new2_raw_replacement));
852
853 const char tried2_raw[]{8, 8, 8, 8};
854 const uint8_t tried2_raw_replacement[]{255, 255, 255, 255}; // 255.255.255.255 is !IsValid()
855 pos = str.find(tried2_raw, 0, sizeof(tried2_raw));
856 BOOST_REQUIRE(pos != std::string::npos);
857 BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
858 memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
859
860 addrman = std::make_unique<AddrManTest>();
861 stream >> *addrman;
862 BOOST_CHECK_EQUAL(addrman->size(), 2);
863}
864
865BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
866{
867 AddrManTest addrman;
868
869 BOOST_CHECK(addrman.size() == 0);
870
871 // Empty addrman should return blank addrman info.
872 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
873
874 // Add twenty two addresses.
875 CNetAddr source = ResolveIP("252.2.2.2");
876 for (unsigned int i = 1; i < 23; i++) {
877 CService addr = ResolveService("250.1.1."+ToString(i));
878 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
879 addrman.Good(addr);
880
881 // No collisions yet.
882 BOOST_CHECK(addrman.size() == i);
883 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
884 }
885
886 // Ensure Good handles duplicates well.
887 for (unsigned int i = 1; i < 23; i++) {
888 CService addr = ResolveService("250.1.1."+ToString(i));
889 addrman.Good(addr);
890
891 BOOST_CHECK(addrman.size() == 22);
892 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
893 }
894
895}
896
897BOOST_AUTO_TEST_CASE(addrman_noevict)
898{
899 AddrManTest addrman;
900
901 // Add 35 addresses.
902 CNetAddr source = ResolveIP("252.2.2.2");
903 for (unsigned int i = 1; i < 36; i++) {
904 CService addr = ResolveService("250.1.1."+ToString(i));
905 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
906 addrman.Good(addr);
907
908 // No collision yet.
909 BOOST_CHECK(addrman.size() == i);
910 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
911 }
912
913 // Collision between 36 and 19.
914 CService addr36 = ResolveService("250.1.1.36");
915 BOOST_CHECK(addrman.Add({CAddress(addr36, NODE_NONE)}, source));
916 addrman.Good(addr36);
917
918 BOOST_CHECK(addrman.size() == 36);
919 BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.19:0");
920
921 // 36 should be discarded and 19 not evicted.
922 addrman.ResolveCollisions();
923 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
924
925 // Lets create two collisions.
926 for (unsigned int i = 37; i < 59; i++) {
927 CService addr = ResolveService("250.1.1."+ToString(i));
928 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
929 addrman.Good(addr);
930
931 BOOST_CHECK(addrman.size() == i);
932 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
933 }
934
935 // Cause a collision.
936 CService addr59 = ResolveService("250.1.1.59");
937 BOOST_CHECK(addrman.Add({CAddress(addr59, NODE_NONE)}, source));
938 addrman.Good(addr59);
939 BOOST_CHECK(addrman.size() == 59);
940
941 BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.10:0");
942
943 // Cause a second collision.
944 BOOST_CHECK(!addrman.Add({CAddress(addr36, NODE_NONE)}, source));
945 addrman.Good(addr36);
946 BOOST_CHECK(addrman.size() == 59);
947
948 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() != "[::]:0");
949 addrman.ResolveCollisions();
950 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
951}
952
953BOOST_AUTO_TEST_CASE(addrman_evictionworks)
954{
955 AddrManTest addrman;
956
957 BOOST_CHECK(addrman.size() == 0);
958
959 // Empty addrman should return blank addrman info.
960 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
961
962 // Add 35 addresses
963 CNetAddr source = ResolveIP("252.2.2.2");
964 for (unsigned int i = 1; i < 36; i++) {
965 CService addr = ResolveService("250.1.1."+ToString(i));
966 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
967 addrman.Good(addr);
968
969 // No collision yet.
970 BOOST_CHECK(addrman.size() == i);
971 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
972 }
973
974 // Collision between 36 and 19.
975 CService addr = ResolveService("250.1.1.36");
976 BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source));
977 addrman.Good(addr);
978
979 BOOST_CHECK_EQUAL(addrman.size(), 36);
980 auto info = addrman.SelectTriedCollision().first;
981 BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0");
982
983 // Ensure test of address fails, so that it is evicted.
984 addrman.SimConnFail(info);
985
986 // Should swap 36 for 19.
987 addrman.ResolveCollisions();
988 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
989
990 // If 36 was swapped for 19, then this should cause no collisions.
991 BOOST_CHECK(!addrman.Add({CAddress(addr, NODE_NONE)}, source));
992 addrman.Good(addr);
993
994 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
995
996 // If we insert 19 it should collide with 36
997 CService addr19 = ResolveService("250.1.1.19");
998 BOOST_CHECK(!addrman.Add({CAddress(addr19, NODE_NONE)}, source));
999 addrman.Good(addr19);
1000
1001 BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.36:0");
1002
1003 addrman.ResolveCollisions();
1004 BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0");
1005}
1006
1008{
1009 AddrManUncorrupted addrmanUncorrupted;
1010
1011 CService addr1, addr2, addr3;
1012 BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
1013 BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
1014 BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
1015 BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false));
1016 BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false));
1017
1018 // Add three addresses to new table.
1020 BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
1021 std::vector<CAddress> addresses{CAddress(addr1, NODE_NONE), CAddress(addr2, NODE_NONE), CAddress(addr3, NODE_NONE)};
1022 BOOST_CHECK(addrmanUncorrupted.Add(addresses, source));
1023 BOOST_CHECK(addrmanUncorrupted.size() == 3);
1024
1025 // Test that the de-serialization does not throw an exception.
1026 CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
1027 bool exceptionThrown = false;
1028 AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
1029
1030 BOOST_CHECK(addrman1.size() == 0);
1031 try {
1032 unsigned char pchMsgTmp[4];
1033 ssPeers1 >> pchMsgTmp;
1034 ssPeers1 >> addrman1;
1035 } catch (const std::exception&) {
1036 exceptionThrown = true;
1037 }
1038
1039 BOOST_CHECK(addrman1.size() == 3);
1040 BOOST_CHECK(exceptionThrown == false);
1041
1042 // Test that ReadFromStream creates an addrman with the correct number of addrs.
1043 CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
1044
1045 AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
1046 BOOST_CHECK(addrman2.size() == 0);
1047 ReadFromStream(addrman2, ssPeers2);
1048 BOOST_CHECK(addrman2.size() == 3);
1049}
1050
1051
1052BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
1053{
1054 AddrManCorrupted addrmanCorrupted;
1055
1056 // Test that the de-serialization of corrupted addrman throws an exception.
1057 CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
1058 bool exceptionThrown = false;
1059 AddrMan addrman1(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
1060 BOOST_CHECK(addrman1.size() == 0);
1061 try {
1062 unsigned char pchMsgTmp[4];
1063 ssPeers1 >> pchMsgTmp;
1064 ssPeers1 >> addrman1;
1065 } catch (const std::exception&) {
1066 exceptionThrown = true;
1067 }
1068 // Even though de-serialization failed addrman is not left in a clean state.
1069 BOOST_CHECK(addrman1.size() == 1);
1070 BOOST_CHECK(exceptionThrown);
1071
1072 // Test that ReadFromStream fails if peers.dat is corrupt
1073 CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
1074
1075 AddrMan addrman2(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 100);
1076 BOOST_CHECK(addrman2.size() == 0);
1077 BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
1078}
1079
1080
void ReadFromStream(AddrMan &addr, CDataStream &ssPeers)
Only used by tests.
Definition: addrdb.cpp:179
static constexpr int ADDRMAN_BUCKET_SIZE
Definition: addrman_impl.h:31
static constexpr int ADDRMAN_NEW_BUCKET_COUNT
Definition: addrman_impl.h:28
static std::vector< bool > FromBytes(const unsigned char *source, int vector_size)
static CService ResolveService(const std::string &ip, uint16_t port=0)
static CDataStream AddrmanToStream(const AddrManSerializationMock &_addrman)
BOOST_AUTO_TEST_CASE(addrman_simple)
static CNetAddr ResolveIP(const std::string &ip)
static unsigned const char asmap_raw[]
Definition: asmap.raw.h:1
const CChainParams & Params()
Return the currently selected parameters.
Extended statistics about a CAddress.
Definition: addrman_impl.h:37
int GetTriedBucket(const uint256 &nKey, const std::vector< bool > &asmap) const
Calculate in which "tried" bucket this entry belongs.
Definition: addrman.cpp:44
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:51
void Serialize(CDataStream &s) const override
Stochastic address manager.
Definition: addrman.h:55
std::pair< CAddress, int64_t > SelectTriedCollision()
Randomly select an address in the tried table that another address is attempting to evict.
Definition: addrman.cpp:1173
const std::unique_ptr< AddrManImpl > m_impl
Definition: addrman.h:56
std::vector< CAddress > GetAddr(size_t max_addresses, size_t max_pct, std::optional< Network > network) const
Return all or many randomly selected addresses, optionally by network.
Definition: addrman.cpp:1183
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, int64_t nTimePenalty=0)
Attempt to add one or more addresses to addrman's new table.
Definition: addrman.cpp:1153
void Good(const CService &addr, int64_t nTime=GetAdjustedTime())
Mark an entry as accessible, possibly moving it from "new" to "tried".
Definition: addrman.cpp:1158
void ResolveCollisions()
See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
Definition: addrman.cpp:1168
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime=GetAdjustedTime())
Mark an entry as connection attempted to.
Definition: addrman.cpp:1163
void Serialize(Stream &s_) const
Definition: addrman.cpp:1128
size_t size() const
Return the number of (unique) addresses in all tables.
Definition: addrman.cpp:1148
std::pair< CAddress, int64_t > Select(bool newOnly=false) const
Choose an address to connect to.
Definition: addrman.cpp:1178
virtual void Serialize(CDataStream &s) const =0
AddrManTest(bool makeDeterministic=true, std::vector< bool > asmap=std::vector< bool >())
std::pair< int, int > GetBucketAndEntry(const CAddress &addr)
void SimConnFail(const CService &addr)
void Delete(int nId)
AddrInfo * Find(const CService &addr, int *pnId=nullptr)
AddrInfo * Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId=nullptr)
void Serialize(CDataStream &s) const override
A CService with information about it as peer.
Definition: protocol.h:359
uint32_t nTime
Always included in serialization.
Definition: protocol.h:440
const CMessageHeader::MessageStartChars & MessageStart() const
Definition: chainparams.h:83
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:205
std::string str() const
Definition: streams.h:242
value_type * data()
Definition: streams.h:264
size_type size() const
Definition: streams.h:255
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:101
Network address.
Definition: netaddress.h:119
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:523
std::string ToString() const
std::vector< unsigned char > GetKey() const
256-bit opaque blob.
Definition: uint256.h:124
static const uint256 ONE
Definition: uint256.h:130
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
BOOST_AUTO_TEST_SUITE_END()
static CService ip(uint32_t i)
static const std::string addr1
Definition: key_tests.cpp:24
static const std::string addr2
Definition: key_tests.cpp:25
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
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
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition: object.cpp:19
#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:274
const char * source
Definition: rpcconsole.cpp:63
@ SER_DISK
Definition: serialize.h:139
@ SER_NETWORK
Definition: serialize.h:138
@ SER_GETHASH
Definition: serialize.h:140
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:87
Basic testing setup.
Definition: setup_common.h:76
#define LOCK(cs)
Definition: sync.h:226
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12