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