| 529 | } |
| 530 | |
| 531 | bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty) |
| 532 | { |
| 533 | AssertLockHeld(cs); |
| 534 | |
| 535 | if (!addr.IsRoutable()) |
| 536 | return false; |
| 537 | |
| 538 | nid_type nId; |
| 539 | AddrInfo* pinfo = Find(addr, &nId); |
| 540 | |
| 541 | // Do not set a penalty for a source's self-announcement |
| 542 | if (addr == source) { |
| 543 | time_penalty = 0s; |
| 544 | } |
| 545 | |
| 546 | if (pinfo) { |
| 547 | // periodically update nTime |
| 548 | const bool currently_online{NodeClock::now() - addr.nTime < 24h}; |
| 549 | const auto update_interval{currently_online ? 1h : 24h}; |
| 550 | if (pinfo->nTime < addr.nTime - update_interval - time_penalty) { |
| 551 | pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty); |
| 552 | } |
| 553 | |
| 554 | // add services |
| 555 | pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices); |
| 556 | |
| 557 | // do not update if no new information is present |
| 558 | if (addr.nTime <= pinfo->nTime) { |
| 559 | return false; |
| 560 | } |
| 561 | |
| 562 | // do not update if the entry was already in the "tried" table |
| 563 | if (pinfo->fInTried) |
| 564 | return false; |
| 565 | |
| 566 | // do not update if the max reference count is reached |
| 567 | if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) |
| 568 | return false; |
| 569 | |
| 570 | // stochastic test: previous nRefCount == N: 2^N times harder to increase it |
| 571 | if (pinfo->nRefCount > 0) { |
| 572 | const int nFactor{1 << pinfo->nRefCount}; |
| 573 | if (insecure_rand.randrange(nFactor) != 0) return false; |
| 574 | } |
| 575 | } else { |
| 576 | pinfo = Create(addr, source, &nId); |
| 577 | pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty); |
| 578 | } |
| 579 | |
| 580 | int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman); |
| 581 | int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); |
| 582 | bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; |
| 583 | if (vvNew[nUBucket][nUBucketPos] != nId) { |
| 584 | if (!fInsert) { |
| 585 | AddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; |
| 586 | if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { |
| 587 | // Overwrite the existing new table entry. |
| 588 | fInsert = true; |
nothing calls this directly
no test coverage detected