You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

addrman.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. // Copyright (c) 2012 Pieter Wuille
  2. // Distributed under the MIT/X11 software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #include "addrman.h"
  5. #include "hash.h"
  6. #include "serialize.h"
  7. using namespace std;
  8. int CAddrInfo::GetTriedBucket(const std::vector<unsigned char> &nKey) const
  9. {
  10. CDataStream ss1(SER_GETHASH, 0);
  11. std::vector<unsigned char> vchKey = GetKey();
  12. ss1 << nKey << vchKey;
  13. uint64_t hash1 = Hash(ss1.begin(), ss1.end()).Get64();
  14. CDataStream ss2(SER_GETHASH, 0);
  15. std::vector<unsigned char> vchGroupKey = GetGroup();
  16. ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP);
  17. uint64_t hash2 = Hash(ss2.begin(), ss2.end()).Get64();
  18. return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
  19. }
  20. int CAddrInfo::GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const
  21. {
  22. CDataStream ss1(SER_GETHASH, 0);
  23. std::vector<unsigned char> vchGroupKey = GetGroup();
  24. std::vector<unsigned char> vchSourceGroupKey = src.GetGroup();
  25. ss1 << nKey << vchGroupKey << vchSourceGroupKey;
  26. uint64_t hash1 = Hash(ss1.begin(), ss1.end()).Get64();
  27. CDataStream ss2(SER_GETHASH, 0);
  28. ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP);
  29. uint64_t hash2 = Hash(ss2.begin(), ss2.end()).Get64();
  30. return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
  31. }
  32. bool CAddrInfo::IsTerrible(int64_t nNow) const
  33. {
  34. if (nLastTry && nLastTry >= nNow-60) // never remove things tried the last minute
  35. return false;
  36. if (nTime > nNow + 10*60) // came in a flying DeLorean
  37. return true;
  38. if (nTime==0 || nNow-nTime > ADDRMAN_HORIZON_DAYS*86400) // not seen in over a month
  39. return true;
  40. if (nLastSuccess==0 && nAttempts>=ADDRMAN_RETRIES) // tried three times and never a success
  41. return true;
  42. if (nNow-nLastSuccess > ADDRMAN_MIN_FAIL_DAYS*86400 && nAttempts>=ADDRMAN_MAX_FAILURES) // 10 successive failures in the last week
  43. return true;
  44. return false;
  45. }
  46. double CAddrInfo::GetChance(int64_t nNow) const
  47. {
  48. double fChance = 1.0;
  49. int64_t nSinceLastSeen = nNow - nTime;
  50. int64_t nSinceLastTry = nNow - nLastTry;
  51. if (nSinceLastSeen < 0) nSinceLastSeen = 0;
  52. if (nSinceLastTry < 0) nSinceLastTry = 0;
  53. fChance *= 600.0 / (600.0 + nSinceLastSeen);
  54. // deprioritize very recent attempts away
  55. if (nSinceLastTry < 60*10)
  56. fChance *= 0.01;
  57. // deprioritize 50% after each failed attempt
  58. for (int n=0; n<nAttempts; n++)
  59. fChance /= 1.5;
  60. return fChance;
  61. }
  62. CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int *pnId)
  63. {
  64. std::map<CNetAddr, int>::iterator it = mapAddr.find(addr);
  65. if (it == mapAddr.end())
  66. return NULL;
  67. if (pnId)
  68. *pnId = (*it).second;
  69. std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second);
  70. if (it2 != mapInfo.end())
  71. return &(*it2).second;
  72. return NULL;
  73. }
  74. CAddrInfo* CAddrMan::Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId)
  75. {
  76. int nId = nIdCount++;
  77. mapInfo[nId] = CAddrInfo(addr, addrSource);
  78. mapAddr[addr] = nId;
  79. mapInfo[nId].nRandomPos = vRandom.size();
  80. vRandom.push_back(nId);
  81. if (pnId)
  82. *pnId = nId;
  83. return &mapInfo[nId];
  84. }
  85. void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
  86. {
  87. if (nRndPos1 == nRndPos2)
  88. return;
  89. assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size());
  90. int nId1 = vRandom[nRndPos1];
  91. int nId2 = vRandom[nRndPos2];
  92. assert(mapInfo.count(nId1) == 1);
  93. assert(mapInfo.count(nId2) == 1);
  94. mapInfo[nId1].nRandomPos = nRndPos2;
  95. mapInfo[nId2].nRandomPos = nRndPos1;
  96. vRandom[nRndPos1] = nId2;
  97. vRandom[nRndPos2] = nId1;
  98. }
  99. int CAddrMan::SelectTried(int nKBucket)
  100. {
  101. std::vector<int> &vTried = vvTried[nKBucket];
  102. // random shuffle the first few elements (using the entire list)
  103. // find the least recently tried among them
  104. int64_t nOldest = -1;
  105. int nOldestPos = -1;
  106. for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++)
  107. {
  108. int nPos = GetRandInt(vTried.size() - i) + i;
  109. int nTemp = vTried[nPos];
  110. vTried[nPos] = vTried[i];
  111. vTried[i] = nTemp;
  112. assert(nOldest == -1 || mapInfo.count(nTemp) == 1);
  113. if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) {
  114. nOldest = nTemp;
  115. nOldestPos = nPos;
  116. }
  117. }
  118. return nOldestPos;
  119. }
  120. int CAddrMan::ShrinkNew(int nUBucket)
  121. {
  122. assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size());
  123. std::set<int> &vNew = vvNew[nUBucket];
  124. // first look for deletable items
  125. for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
  126. {
  127. assert(mapInfo.count(*it));
  128. CAddrInfo &info = mapInfo[*it];
  129. if (info.IsTerrible())
  130. {
  131. if (--info.nRefCount == 0)
  132. {
  133. SwapRandom(info.nRandomPos, vRandom.size()-1);
  134. vRandom.pop_back();
  135. mapAddr.erase(info);
  136. mapInfo.erase(*it);
  137. nNew--;
  138. }
  139. vNew.erase(it);
  140. return 0;
  141. }
  142. }
  143. // otherwise, select four randomly, and pick the oldest of those to replace
  144. int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())};
  145. int nI = 0;
  146. int nOldest = -1;
  147. for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
  148. {
  149. if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3])
  150. {
  151. assert(nOldest == -1 || mapInfo.count(*it) == 1);
  152. if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime)
  153. nOldest = *it;
  154. }
  155. nI++;
  156. }
  157. assert(mapInfo.count(nOldest) == 1);
  158. CAddrInfo &info = mapInfo[nOldest];
  159. if (--info.nRefCount == 0)
  160. {
  161. SwapRandom(info.nRandomPos, vRandom.size()-1);
  162. vRandom.pop_back();
  163. mapAddr.erase(info);
  164. mapInfo.erase(nOldest);
  165. nNew--;
  166. }
  167. vNew.erase(nOldest);
  168. return 1;
  169. }
  170. void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
  171. {
  172. assert(vvNew[nOrigin].count(nId) == 1);
  173. // remove the entry from all new buckets
  174. for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++)
  175. {
  176. if ((*it).erase(nId))
  177. info.nRefCount--;
  178. }
  179. nNew--;
  180. assert(info.nRefCount == 0);
  181. // what tried bucket to move the entry to
  182. int nKBucket = info.GetTriedBucket(nKey);
  183. std::vector<int> &vTried = vvTried[nKBucket];
  184. // first check whether there is place to just add it
  185. if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE)
  186. {
  187. vTried.push_back(nId);
  188. nTried++;
  189. info.fInTried = true;
  190. return;
  191. }
  192. // otherwise, find an item to evict
  193. int nPos = SelectTried(nKBucket);
  194. // find which new bucket it belongs to
  195. assert(mapInfo.count(vTried[nPos]) == 1);
  196. int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey);
  197. std::set<int> &vNew = vvNew[nUBucket];
  198. // remove the to-be-replaced tried entry from the tried set
  199. CAddrInfo& infoOld = mapInfo[vTried[nPos]];
  200. infoOld.fInTried = false;
  201. infoOld.nRefCount = 1;
  202. // do not update nTried, as we are going to move something else there immediately
  203. // check whether there is place in that one,
  204. if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE)
  205. {
  206. // if so, move it back there
  207. vNew.insert(vTried[nPos]);
  208. } else {
  209. // otherwise, move it to the new bucket nId came from (there is certainly place there)
  210. vvNew[nOrigin].insert(vTried[nPos]);
  211. }
  212. nNew++;
  213. vTried[nPos] = nId;
  214. // we just overwrote an entry in vTried; no need to update nTried
  215. info.fInTried = true;
  216. return;
  217. }
  218. void CAddrMan::Good_(const CService &addr, int64_t nTime)
  219. {
  220. int nId;
  221. CAddrInfo *pinfo = Find(addr, &nId);
  222. // if not found, bail out
  223. if (!pinfo)
  224. return;
  225. CAddrInfo &info = *pinfo;
  226. // check whether we are talking about the exact same CService (including same port)
  227. if (info != addr)
  228. return;
  229. // update info
  230. info.nLastSuccess = nTime;
  231. info.nLastTry = nTime;
  232. info.nTime = nTime;
  233. info.nAttempts = 0;
  234. // if it is already in the tried set, don't do anything else
  235. if (info.fInTried)
  236. return;
  237. // find a bucket it is in now
  238. int nRnd = GetRandInt(vvNew.size());
  239. int nUBucket = -1;
  240. for (unsigned int n = 0; n < vvNew.size(); n++)
  241. {
  242. int nB = (n+nRnd) % vvNew.size();
  243. std::set<int> &vNew = vvNew[nB];
  244. if (vNew.count(nId))
  245. {
  246. nUBucket = nB;
  247. break;
  248. }
  249. }
  250. // if no bucket is found, something bad happened;
  251. // TODO: maybe re-add the node, but for now, just bail out
  252. if (nUBucket == -1) return;
  253. LogPrint("addrman", "Moving %s to tried\n", addr.ToString().c_str());
  254. // move nId to the tried tables
  255. MakeTried(info, nId, nUBucket);
  256. }
  257. bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty)
  258. {
  259. if (!addr.IsRoutable())
  260. return false;
  261. bool fNew = false;
  262. int nId;
  263. CAddrInfo *pinfo = Find(addr, &nId);
  264. if (pinfo)
  265. {
  266. // periodically update nTime
  267. bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
  268. int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
  269. if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
  270. pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty);
  271. // add services
  272. pinfo->nServices |= addr.nServices;
  273. // do not update if no new information is present
  274. if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime))
  275. return false;
  276. // do not update if the entry was already in the "tried" table
  277. if (pinfo->fInTried)
  278. return false;
  279. // do not update if the max reference count is reached
  280. if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS)
  281. return false;
  282. // stochastic test: previous nRefCount == N: 2^N times harder to increase it
  283. int nFactor = 1;
  284. for (int n=0; n<pinfo->nRefCount; n++)
  285. nFactor *= 2;
  286. if (nFactor > 1 && (GetRandInt(nFactor) != 0))
  287. return false;
  288. } else {
  289. pinfo = Create(addr, source, &nId);
  290. pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
  291. nNew++;
  292. fNew = true;
  293. }
  294. int nUBucket = pinfo->GetNewBucket(nKey, source);
  295. std::set<int> &vNew = vvNew[nUBucket];
  296. if (!vNew.count(nId))
  297. {
  298. pinfo->nRefCount++;
  299. if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE)
  300. ShrinkNew(nUBucket);
  301. vvNew[nUBucket].insert(nId);
  302. }
  303. return fNew;
  304. }
  305. void CAddrMan::Attempt_(const CService &addr, int64_t nTime)
  306. {
  307. CAddrInfo *pinfo = Find(addr);
  308. // if not found, bail out
  309. if (!pinfo)
  310. return;
  311. CAddrInfo &info = *pinfo;
  312. // check whether we are talking about the exact same CService (including same port)
  313. if (info != addr)
  314. return;
  315. // update info
  316. info.nLastTry = nTime;
  317. info.nAttempts++;
  318. }
  319. CAddress CAddrMan::Select_(int nUnkBias)
  320. {
  321. if (size() == 0)
  322. return CAddress();
  323. double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
  324. double nCorNew = sqrt(nNew) * nUnkBias;
  325. if ((nCorTried + nCorNew)*GetRandInt(1<<30)/(1<<30) < nCorTried)
  326. {
  327. // use a tried node
  328. double fChanceFactor = 1.0;
  329. while(1)
  330. {
  331. int nKBucket = GetRandInt(vvTried.size());
  332. std::vector<int> &vTried = vvTried[nKBucket];
  333. if (vTried.size() == 0) continue;
  334. int nPos = GetRandInt(vTried.size());
  335. assert(mapInfo.count(vTried[nPos]) == 1);
  336. CAddrInfo &info = mapInfo[vTried[nPos]];
  337. if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
  338. return info;
  339. fChanceFactor *= 1.2;
  340. }
  341. } else {
  342. // use a new node
  343. double fChanceFactor = 1.0;
  344. while(1)
  345. {
  346. int nUBucket = GetRandInt(vvNew.size());
  347. std::set<int> &vNew = vvNew[nUBucket];
  348. if (vNew.size() == 0) continue;
  349. int nPos = GetRandInt(vNew.size());
  350. std::set<int>::iterator it = vNew.begin();
  351. while (nPos--)
  352. it++;
  353. assert(mapInfo.count(*it) == 1);
  354. CAddrInfo &info = mapInfo[*it];
  355. if (GetRandInt(1<<30) < fChanceFactor*info.GetChance()*(1<<30))
  356. return info;
  357. fChanceFactor *= 1.2;
  358. }
  359. }
  360. }
  361. #ifdef DEBUG_ADDRMAN
  362. int CAddrMan::Check_()
  363. {
  364. std::set<int> setTried;
  365. std::map<int, int> mapNew;
  366. if (vRandom.size() != nTried + nNew) return -7;
  367. for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++)
  368. {
  369. int n = (*it).first;
  370. CAddrInfo &info = (*it).second;
  371. if (info.fInTried)
  372. {
  373. if (!info.nLastSuccess) return -1;
  374. if (info.nRefCount) return -2;
  375. setTried.insert(n);
  376. } else {
  377. if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return -3;
  378. if (!info.nRefCount) return -4;
  379. mapNew[n] = info.nRefCount;
  380. }
  381. if (mapAddr[info] != n) return -5;
  382. if (info.nRandomPos<0 || info.nRandomPos>=vRandom.size() || vRandom[info.nRandomPos] != n) return -14;
  383. if (info.nLastTry < 0) return -6;
  384. if (info.nLastSuccess < 0) return -8;
  385. }
  386. if (setTried.size() != nTried) return -9;
  387. if (mapNew.size() != nNew) return -10;
  388. for (int n=0; n<vvTried.size(); n++)
  389. {
  390. std::vector<int> &vTried = vvTried[n];
  391. for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++)
  392. {
  393. if (!setTried.count(*it)) return -11;
  394. setTried.erase(*it);
  395. }
  396. }
  397. for (int n=0; n<vvNew.size(); n++)
  398. {
  399. std::set<int> &vNew = vvNew[n];
  400. for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++)
  401. {
  402. if (!mapNew.count(*it)) return -12;
  403. if (--mapNew[*it] == 0)
  404. mapNew.erase(*it);
  405. }
  406. }
  407. if (setTried.size()) return -13;
  408. if (mapNew.size()) return -15;
  409. return 0;
  410. }
  411. #endif
  412. void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
  413. {
  414. int nNodes = ADDRMAN_GETADDR_MAX_PCT*vRandom.size()/100;
  415. if (nNodes > ADDRMAN_GETADDR_MAX)
  416. nNodes = ADDRMAN_GETADDR_MAX;
  417. // perform a random shuffle over the first nNodes elements of vRandom (selecting from all)
  418. for (int n = 0; n<nNodes; n++)
  419. {
  420. int nRndPos = GetRandInt(vRandom.size() - n) + n;
  421. SwapRandom(n, nRndPos);
  422. assert(mapInfo.count(vRandom[n]) == 1);
  423. vAddr.push_back(mapInfo[vRandom[n]]);
  424. }
  425. }
  426. void CAddrMan::Connected_(const CService &addr, int64_t nTime)
  427. {
  428. CAddrInfo *pinfo = Find(addr);
  429. // if not found, bail out
  430. if (!pinfo)
  431. return;
  432. CAddrInfo &info = *pinfo;
  433. // check whether we are talking about the exact same CService (including same port)
  434. if (info != addr)
  435. return;
  436. // update info
  437. int64_t nUpdateInterval = 20 * 60;
  438. if (nTime - info.nTime > nUpdateInterval)
  439. info.nTime = nTime;
  440. }