| 540 | } |
| 541 | |
| 542 | bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) |
| 543 | { |
| 544 | AssertLockHeld(cs); |
| 545 | |
| 546 | if (!addr.IsRoutable()) |
| 547 | return false; |
| 548 | |
| 549 | nid_type nId; |
| 550 | AddrInfo* pinfo = Find(addr, &nId); |
| 551 | |
| 552 | // Do not set a penalty for a source's self-announcement |
| 553 | if (addr == source) { |
| 554 | nTimePenalty = 0; |
| 555 | } |
| 556 | |
| 557 | if (pinfo) { |
| 558 | // periodically update nTime |
| 559 | bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); |
| 560 | int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); |
| 561 | if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) |
| 562 | pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); |
| 563 | |
| 564 | // add services |
| 565 | pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices); |
| 566 | |
| 567 | // do not update if no new information is present |
| 568 | if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) |
| 569 | return false; |
| 570 | |
| 571 | // do not update if the entry was already in the "tried" table |
| 572 | if (pinfo->fInTried) |
| 573 | return false; |
| 574 | |
| 575 | // do not update if the max reference count is reached |
| 576 | if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) |
| 577 | return false; |
| 578 | |
| 579 | // stochastic test: previous nRefCount == N: 2^N times harder to increase it |
| 580 | int nFactor = 1; |
| 581 | for (int n = 0; n < pinfo->nRefCount; n++) |
| 582 | nFactor *= 2; |
| 583 | if (nFactor > 1 && (insecure_rand.randrange(nFactor) != 0)) |
| 584 | return false; |
| 585 | } else { |
| 586 | pinfo = Create(addr, source, &nId); |
| 587 | pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); |
| 588 | nNew++; |
| 589 | } |
| 590 | |
| 591 | int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap); |
| 592 | int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); |
| 593 | bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; |
| 594 | if (vvNew[nUBucket][nUBucketPos] != nId) { |
| 595 | if (!fInsert) { |
| 596 | AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; |
| 597 | if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { |
| 598 | // Overwrite the existing new table entry. |
| 599 | fInsert = true; |
nothing calls this directly
no test coverage detected