Line data Source code
1 : // Copyright (c) 2012 Pieter Wuille
2 : // Copyright (c) 2012-2014 The Bitcoin developers
3 : // Copyright (c) 2017-2021 The PIVX Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #include "addrman.h"
8 :
9 : #include "hash.h"
10 : #include "logging.h"
11 : #include "netaddress.h"
12 : #include "optional.h"
13 : #include "streams.h"
14 : #include "serialize.h"
15 :
16 :
17 1843 : int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
18 : {
19 5529 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash();
20 5529 : uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetHash().GetCheapHash();
21 1843 : int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
22 1843 : uint32_t mapped_as = GetMappedAS(asmap);
23 1843 : LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to tried bucket %i\n", ToStringIP(), mapped_as, tried_bucket);
24 1843 : return tried_bucket;
25 : }
26 :
27 15582 : int CAddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool> &asmap) const
28 : {
29 15582 : std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
30 46746 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetHash().GetCheapHash();
31 31164 : uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetHash().GetCheapHash();
32 15582 : int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT;
33 15582 : uint32_t mapped_as = GetMappedAS(asmap);
34 25212 : LogPrint(BCLog::NET, "IP %s mapped to AS%i belongs to new bucket %i\n", ToStringIP(), mapped_as, new_bucket);
35 31164 : return new_bucket;
36 : }
37 :
38 13079 : int CAddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
39 : {
40 40050 : uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? 'N' : 'K') << nBucket << GetKey()).GetHash().GetCheapHash();
41 13079 : return hash1 % ADDRMAN_BUCKET_SIZE;
42 : }
43 :
44 10000 : bool CAddrInfo::IsTerrible(int64_t nNow) const
45 : {
46 10000 : if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
47 : return false;
48 :
49 9933 : if (nTime > nNow + 10 * 60) // came in a flying DeLorean
50 : return true;
51 :
52 9930 : if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history
53 : return true;
54 :
55 9929 : if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
56 : return true;
57 :
58 9929 : if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
59 0 : return true;
60 :
61 : return false;
62 : }
63 :
64 5806 : double CAddrInfo::GetChance(int64_t nNow) const
65 : {
66 5806 : double fChance = 1.0;
67 5806 : int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
68 :
69 : // deprioritize very recent attempts away
70 5806 : if (nSinceLastTry < 60 * 10)
71 5570 : fChance *= 0.01;
72 :
73 : // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
74 5806 : fChance *= pow(0.66, std::min(nAttempts, 8));
75 :
76 5806 : return fChance;
77 : }
78 :
79 14954 : CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
80 : {
81 14954 : std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
82 14954 : if (it == mapAddr.end())
83 : return nullptr;
84 457 : if (pnId)
85 440 : *pnId = (*it).second;
86 457 : std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
87 457 : if (it2 != mapInfo.end())
88 457 : return &(*it2).second;
89 : return nullptr;
90 : }
91 :
92 11858 : CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
93 : {
94 11858 : int nId = nIdCount++;
95 11858 : mapInfo[nId] = CAddrInfo(addr, addrSource);
96 11858 : mapAddr[addr] = nId;
97 11858 : mapInfo[nId].nRandomPos = vRandom.size();
98 11858 : vRandom.push_back(nId);
99 11858 : if (pnId)
100 11858 : *pnId = nId;
101 11858 : return &mapInfo[nId];
102 : }
103 :
104 27683 : void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
105 : {
106 27683 : if (nRndPos1 == nRndPos2)
107 711 : return;
108 :
109 26972 : assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
110 :
111 26972 : int nId1 = vRandom[nRndPos1];
112 26972 : int nId2 = vRandom[nRndPos2];
113 :
114 26972 : assert(mapInfo.count(nId1) == 1);
115 26972 : assert(mapInfo.count(nId2) == 1);
116 :
117 26972 : mapInfo[nId1].nRandomPos = nRndPos2;
118 26972 : mapInfo[nId2].nRandomPos = nRndPos1;
119 :
120 26972 : vRandom[nRndPos1] = nId2;
121 26972 : vRandom[nRndPos2] = nId1;
122 : }
123 :
124 676 : void CAddrMan::Delete(int nId)
125 : {
126 676 : assert(mapInfo.count(nId) != 0);
127 676 : CAddrInfo& info = mapInfo[nId];
128 676 : assert(!info.fInTried);
129 676 : assert(info.nRefCount == 0);
130 :
131 676 : SwapRandom(info.nRandomPos, vRandom.size() - 1);
132 676 : vRandom.pop_back();
133 676 : mapAddr.erase(info);
134 676 : mapInfo.erase(nId);
135 676 : nNew--;
136 676 : }
137 :
138 11186 : void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
139 : {
140 : // if there is an entry in the specified bucket, delete it.
141 11186 : if (vvNew[nUBucket][nUBucketPos] != -1) {
142 4 : int nIdDelete = vvNew[nUBucket][nUBucketPos];
143 4 : CAddrInfo& infoDelete = mapInfo[nIdDelete];
144 4 : assert(infoDelete.nRefCount > 0);
145 4 : infoDelete.nRefCount--;
146 4 : vvNew[nUBucket][nUBucketPos] = -1;
147 4 : if (infoDelete.nRefCount == 0) {
148 4 : Delete(nIdDelete);
149 : }
150 : }
151 11186 : }
152 :
153 394 : void CAddrMan::MakeTried(CAddrInfo& info, int nId)
154 : {
155 : // remove the entry from all new buckets
156 394 : const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
157 394 : for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
158 394 : const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
159 394 : const int pos{info.GetBucketPosition(nKey, true, bucket)};
160 394 : if (vvNew[bucket][pos] == nId) {
161 394 : vvNew[bucket][pos] = -1;
162 394 : info.nRefCount--;
163 394 : if (info.nRefCount == 0) break;
164 : }
165 : }
166 394 : nNew--;
167 :
168 394 : assert(info.nRefCount == 0);
169 :
170 : // which tried bucket to move the entry to
171 394 : int nKBucket = info.GetTriedBucket(nKey, m_asmap);
172 394 : int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
173 :
174 : // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
175 394 : if (vvTried[nKBucket][nKBucketPos] != -1) {
176 : // find an item to evict
177 1 : int nIdEvict = vvTried[nKBucket][nKBucketPos];
178 1 : assert(mapInfo.count(nIdEvict) == 1);
179 1 : CAddrInfo& infoOld = mapInfo[nIdEvict];
180 :
181 : // Remove the to-be-evicted item from the tried set.
182 1 : infoOld.fInTried = false;
183 1 : vvTried[nKBucket][nKBucketPos] = -1;
184 1 : nTried--;
185 :
186 : // find which new bucket it belongs to
187 1 : int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
188 1 : int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
189 1 : ClearNew(nUBucket, nUBucketPos);
190 1 : assert(vvNew[nUBucket][nUBucketPos] == -1);
191 :
192 : // Enter it into the new set again.
193 1 : infoOld.nRefCount = 1;
194 1 : vvNew[nUBucket][nUBucketPos] = nIdEvict;
195 1 : nNew++;
196 : }
197 394 : assert(vvTried[nKBucket][nKBucketPos] == -1);
198 :
199 394 : vvTried[nKBucket][nKBucketPos] = nId;
200 394 : nTried++;
201 394 : info.fInTried = true;
202 394 : }
203 :
204 1094 : void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
205 : {
206 1094 : int nId;
207 :
208 1094 : nLastGood = nTime;
209 :
210 1094 : CAddrInfo* pinfo = Find(addr, &nId);
211 :
212 : // if not found, bail out
213 1094 : if (!pinfo)
214 685 : return;
215 :
216 434 : CAddrInfo& info = *pinfo;
217 :
218 : // check whether we are talking about the exact same CService (including same port)
219 434 : if (info != addr)
220 : return;
221 :
222 : // update info
223 433 : info.nLastSuccess = nTime;
224 433 : info.nLastTry = nTime;
225 433 : info.nAttempts = 0;
226 : // nTime is not updated here, to avoid leaking information about
227 : // currently-connected peers.
228 :
229 : // if it is already in the tried set, don't do anything else
230 433 : if (info.fInTried)
231 : return;
232 :
233 : // if it is not in new, something bad happened
234 409 : if (info.nRefCount <= 0) {
235 : return;
236 : }
237 :
238 : // which tried bucket to move the entry to
239 409 : int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
240 409 : int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
241 :
242 : // Will moving this address into tried evict another entry?
243 409 : if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
244 : // Output the entry we'd be colliding with, for debugging purposes
245 15 : auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
246 15 : LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
247 15 : if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
248 15 : m_tried_collisions.insert(nId);
249 15 : }
250 : } else {
251 394 : LogPrint(BCLog::ADDRMAN, "Moving %s to tried\n", addr.ToString());
252 :
253 : // move nId to the tried tables
254 394 : MakeTried(info, nId);
255 : }
256 : }
257 :
258 12464 : bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
259 : {
260 12464 : if (!addr.IsRoutable())
261 : return false;
262 :
263 11862 : bool fNew = false;
264 11862 : int nId;
265 11862 : CAddrInfo* pinfo = Find(addr, &nId);
266 :
267 : // Do not set a penalty for a source's self-announcement
268 11862 : if (addr == source) {
269 11515 : nTimePenalty = 0;
270 : }
271 :
272 11862 : if (pinfo) {
273 : // periodically update nTime
274 6 : bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
275 6 : int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
276 6 : if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
277 0 : pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
278 :
279 : // add services
280 6 : pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices);
281 :
282 : // do not update if no new information is present
283 6 : if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
284 : return false;
285 :
286 : // do not update if the entry was already in the "tried" table
287 0 : if (pinfo->fInTried)
288 : return false;
289 :
290 : // do not update if the max reference count is reached
291 0 : if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
292 : return false;
293 :
294 : // stochastic test: previous nRefCount == N: 2^N times harder to increase it
295 : int nFactor = 1;
296 0 : for (int n = 0; n < pinfo->nRefCount; n++)
297 0 : nFactor *= 2;
298 0 : if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0))
299 : return false;
300 : } else {
301 11856 : pinfo = Create(addr, source, &nId);
302 11856 : pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
303 11856 : nNew++;
304 11856 : fNew = true;
305 : }
306 :
307 11856 : int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
308 11856 : int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
309 11856 : if (vvNew[nUBucket][nUBucketPos] != nId) {
310 11856 : bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
311 11856 : if (!fInsert) {
312 675 : CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]];
313 675 : if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) {
314 : // Overwrite the existing new table entry.
315 : fInsert = true;
316 : }
317 : }
318 11852 : if (fInsert) {
319 11185 : ClearNew(nUBucket, nUBucketPos);
320 11185 : pinfo->nRefCount++;
321 11185 : vvNew[nUBucket][nUBucketPos] = nId;
322 : } else {
323 671 : if (pinfo->nRefCount == 0) {
324 671 : Delete(nId);
325 : }
326 : }
327 : }
328 : return fNew;
329 : }
330 :
331 703 : void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
332 : {
333 703 : CAddrInfo* pinfo = Find(addr);
334 :
335 : // if not found, bail out
336 703 : if (!pinfo)
337 : return;
338 :
339 13 : CAddrInfo& info = *pinfo;
340 :
341 : // check whether we are talking about the exact same CService (including same port)
342 13 : if (info != addr)
343 : return;
344 :
345 : // update info
346 13 : info.nLastTry = nTime;
347 13 : if (fCountFailure && info.nLastCountAttempt < nLastGood) {
348 0 : info.nLastCountAttempt = nTime;
349 0 : info.nAttempts++;
350 : }
351 : }
352 :
353 38393 : CAddrInfo CAddrMan::Select_(bool newOnly)
354 : {
355 38393 : if (size() == 0)
356 37767 : return CAddrInfo();
357 :
358 626 : if (newOnly && nNew == 0)
359 1 : return CAddrInfo();
360 :
361 : // Use a 50% chance for choosing between tried and new table entries.
362 625 : if (!newOnly && (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
363 : // use a tried node
364 : double fChanceFactor = 1.0;
365 321 : while (1) {
366 166 : int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
367 332 : int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
368 778111 : while (vvTried[nKBucket][nKBucketPos] == -1) {
369 777945 : nKBucket = (nKBucket + insecure_rand.randbits(ADDRMAN_TRIED_BUCKET_COUNT_LOG2)) % ADDRMAN_TRIED_BUCKET_COUNT;
370 777945 : nKBucketPos = (nKBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
371 : }
372 166 : int nId = vvTried[nKBucket][nKBucketPos];
373 166 : assert(mapInfo.count(nId) == 1);
374 166 : CAddrInfo& info = mapInfo[nId];
375 166 : if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
376 11 : return info;
377 155 : fChanceFactor *= 1.2;
378 155 : }
379 : } else {
380 : // use a new node
381 : double fChanceFactor = 1.0;
382 10666 : while (1) {
383 5640 : int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
384 11280 : int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
385 326156030 : while (vvNew[nUBucket][nUBucketPos] == -1) {
386 326150016 : nUBucket = (nUBucket + insecure_rand.randbits(ADDRMAN_NEW_BUCKET_COUNT_LOG2)) % ADDRMAN_NEW_BUCKET_COUNT;
387 326150016 : nUBucketPos = (nUBucketPos + insecure_rand.randbits(ADDRMAN_BUCKET_SIZE_LOG2)) % ADDRMAN_BUCKET_SIZE;
388 : }
389 5640 : int nId = vvNew[nUBucket][nUBucketPos];
390 5640 : assert(mapInfo.count(nId) == 1);
391 5640 : CAddrInfo& info = mapInfo[nId];
392 5640 : if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30))
393 614 : return info;
394 5026 : fChanceFactor *= 1.2;
395 5026 : }
396 : }
397 : }
398 :
399 : #ifdef DEBUG_ADDRMAN
400 : int CAddrMan::Check_()
401 : {
402 : std::set<int> setTried;
403 : std::map<int, int> mapNew;
404 :
405 : if (vRandom.size() != nTried + nNew)
406 : return -7;
407 :
408 : for (const auto& entry : mapInfo) {
409 : int n = entry.first;
410 : const CAddrInfo& info = entry.second;
411 : if (info.fInTried) {
412 : if (!info.nLastSuccess)
413 : return -1;
414 : if (info.nRefCount)
415 : return -2;
416 : setTried.insert(n);
417 : } else {
418 : if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
419 : return -3;
420 : if (!info.nRefCount)
421 : return -4;
422 : mapNew[n] = info.nRefCount;
423 : }
424 : if (mapAddr[info] != n)
425 : return -5;
426 : if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
427 : return -14;
428 : if (info.nLastTry < 0)
429 : return -6;
430 : if (info.nLastSuccess < 0)
431 : return -8;
432 : }
433 :
434 : if (setTried.size() != nTried)
435 : return -9;
436 : if (mapNew.size() != nNew)
437 : return -10;
438 :
439 : for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) {
440 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
441 : if (vvTried[n][i] != -1) {
442 : if (!setTried.count(vvTried[n][i]))
443 : return -11;
444 : if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n)
445 : return -17;
446 : if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != i)
447 : return -18;
448 : setTried.erase(vvTried[n][i]);
449 : }
450 : }
451 : }
452 :
453 : for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) {
454 : for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
455 : if (vvNew[n][i] != -1) {
456 : if (!mapNew.count(vvNew[n][i]))
457 : return -12;
458 : if (mapInfo[vvNew[n][i]].GetBucketPosition(nKey, true, n) != i)
459 : return -19;
460 : if (--mapNew[vvNew[n][i]] == 0)
461 : mapNew.erase(vvNew[n][i]);
462 : }
463 : }
464 : }
465 :
466 : if (setTried.size())
467 : return -13;
468 : if (mapNew.size())
469 : return -15;
470 : if (nKey.IsNull())
471 : return -16;
472 :
473 : return 0;
474 : }
475 : #endif
476 :
477 660 : void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, Optional<Network> network)
478 : {
479 660 : size_t nNodes = vRandom.size();
480 660 : if (max_pct != 0) {
481 651 : nNodes = max_pct * nNodes / 100;
482 : }
483 660 : if (max_addresses != 0) {
484 657 : nNodes = std::min(nNodes, max_addresses);
485 : }
486 :
487 : // gather a list of random nodes, skipping those of low quality
488 660 : const int64_t now{GetAdjustedTime()};
489 27667 : for (unsigned int n = 0; n < vRandom.size(); n++) {
490 27013 : if (vAddr.size() >= nNodes)
491 : break;
492 :
493 27007 : int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;
494 27007 : SwapRandom(n, nRndPos);
495 27007 : assert(mapInfo.count(vRandom[n]) == 1);
496 :
497 27007 : const CAddrInfo& ai = mapInfo[vRandom[n]];
498 :
499 : // Filter by network (optional)
500 27007 : if (network != nullopt && ai.GetNetClass() != network) continue;
501 :
502 : // Filter for quality
503 9325 : if (ai.IsTerrible(now)) continue;
504 :
505 9325 : vAddr.push_back(ai);
506 : }
507 660 : }
508 :
509 642 : void CAddrMan::Connected_(const CService& addr, int64_t nTime)
510 : {
511 642 : CAddrInfo* pinfo = Find(addr);
512 :
513 : // if not found, bail out
514 642 : if (!pinfo)
515 : return;
516 :
517 0 : CAddrInfo& info = *pinfo;
518 :
519 : // check whether we are talking about the exact same CService (including same port)
520 0 : if (info != addr)
521 : return;
522 :
523 : // update info
524 0 : int64_t nUpdateInterval = 20 * 60;
525 0 : if (nTime - info.nTime > nUpdateInterval)
526 0 : info.nTime = nTime;
527 : }
528 :
529 648 : void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
530 : {
531 648 : CAddrInfo* pinfo = Find(addr);
532 :
533 : // if not found, bail out
534 648 : if (!pinfo)
535 : return;
536 :
537 0 : CAddrInfo& info = *pinfo;
538 :
539 : // check whether we are talking about the exact same CService (including same port)
540 0 : if (info != addr)
541 : return;
542 :
543 : // update info
544 0 : info.nServices = nServices;
545 : }
546 :
547 37781 : void CAddrMan::ResolveCollisions_()
548 : {
549 37786 : for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
550 5 : int id_new = *it;
551 :
552 5 : bool erase_collision = false;
553 :
554 : // If id_new not found in mapInfo remove it from m_tried_collisions
555 5 : if (mapInfo.count(id_new) != 1) {
556 : erase_collision = true;
557 : } else {
558 5 : CAddrInfo& info_new = mapInfo[id_new];
559 :
560 : // Which tried bucket to move the entry to.
561 5 : int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
562 5 : int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
563 5 : if (!info_new.IsValid()) { // id_new may no longer map to a valid address
564 : erase_collision = true;
565 5 : } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { // The position in the tried bucket is not empty
566 :
567 : // Get the to-be-evicted address that is being tested
568 5 : int id_old = vvTried[tried_bucket][tried_bucket_pos];
569 5 : CAddrInfo& info_old = mapInfo[id_old];
570 :
571 : // Has successfully connected in last X hours
572 5 : if (GetAdjustedTime() - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
573 : erase_collision = true;
574 1 : } else if (GetAdjustedTime() - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
575 :
576 : // Give address at least 60 seconds to successfully connect
577 1 : if (GetAdjustedTime() - info_old.nLastTry > 60) {
578 1 : LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
579 :
580 : // Replaces an existing address already in the tried table with the new address
581 1 : Good_(info_new, false, GetAdjustedTime());
582 : erase_collision = true;
583 : }
584 0 : } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
585 : // If the collision hasn't resolved in some reasonable amount of time,
586 : // just evict the old entry -- we must not be able to
587 : // connect to it for some reason.
588 0 : LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
589 0 : Good_(info_new, false, GetAdjustedTime());
590 : erase_collision = true;
591 : }
592 : } else { // Collision is not actually a collision anymore
593 0 : Good_(info_new, false, GetAdjustedTime());
594 : erase_collision = true;
595 : }
596 : }
597 :
598 5 : if (erase_collision) {
599 5 : m_tried_collisions.erase(it++);
600 : } else {
601 5 : it++;
602 : }
603 : }
604 37781 : }
605 :
606 38474 : CAddrInfo CAddrMan::SelectTriedCollision_()
607 : {
608 38474 : if (m_tried_collisions.size() == 0) return CAddrInfo();
609 :
610 5 : std::set<int>::iterator it = m_tried_collisions.begin();
611 :
612 : // Selects a random element from m_tried_collisions
613 10 : std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));
614 5 : int id_new = *it;
615 :
616 : // If id_new not found in mapInfo remove it from m_tried_collisions
617 5 : if (mapInfo.count(id_new) != 1) {
618 0 : m_tried_collisions.erase(it);
619 0 : return CAddrInfo();
620 : }
621 :
622 5 : CAddrInfo& newInfo = mapInfo[id_new];
623 :
624 : // which tried bucket to move the entry to
625 5 : int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
626 5 : int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
627 :
628 5 : int id_old = vvTried[tried_bucket][tried_bucket_pos];
629 :
630 5 : return mapInfo[id_old];
631 : }
632 :
633 5 : std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
634 : {
635 5 : std::vector<bool> bits;
636 5 : FILE *filestr = fsbridge::fopen(path, "rb");
637 10 : CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
638 5 : if (file.IsNull()) {
639 0 : LogPrintf("Failed to open asmap file from disk\n");
640 : return bits;
641 : }
642 5 : fseek(filestr, 0, SEEK_END);
643 5 : int length = ftell(filestr);
644 5 : LogPrintf("Opened asmap file %s (%d bytes) from disk\n", path, length);
645 5 : fseek(filestr, 0, SEEK_SET);
646 5 : char cur_byte;
647 241 : for (int i = 0; i < length; ++i) {
648 236 : file >> cur_byte;
649 2124 : for (int bit = 0; bit < 8; ++bit) {
650 1888 : bits.push_back((cur_byte >> bit) & 1);
651 : }
652 : }
653 : return bits;
654 : }
|