Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
751} else {752break;753}754}755}757// If the bucket is entirely empty, start over with a (likely) different one.758if (i == ADDRMAN_BUCKET_SIZE) continue;760// Find the entry to return.761const auto it_found{mapInfo.find(node_id)};762assert(it_found != mapInfo.end());763const AddrInfo& info{it_found->second};765// With probability GetChance() * chance_factor, return the entry.766if (insecure_rand.randbits<30>() < chance_factor * info.GetChance() * (1 << 30)) {767LogDebug(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");768return {info, info.m_last_try};769}771// Otherwise start over with a (likely) different bucket, and increased chance factor.772chance_factor *= 1.2;773}774}776nid_type AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const777{778AssertLockHeld(cs);780if (use_tried) {781if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_TRIED_BUCKET_COUNT)) {782return vvTried[bucket][position];783}784} else {785if (Assume(position < ADDRMAN_BUCKET_SIZE) && Assume(bucket < ADDRMAN_NEW_BUCKET_COUNT)) {786return vvNew[bucket][position];787}788}790return -1;791}793std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network, const bool filtered) const794{795AssertLockHeld(cs);796Assume(max_pct <= 100);798size_t nNodes = vRandom.size();799if (max_pct != 0) {800max_pct = std::min(max_pct, size_t{100});801nNodes = max_pct * nNodes / 100;802}803if (max_addresses != 0) {804nNodes = std::min(nNodes, max_addresses);805}807// gather a list of random nodes, skipping those of low quality808const auto now{Now<NodeSeconds>()};809std::vector<CAddress> addresses;810addresses.reserve(nNodes);811for (unsigned int n = 0; n < vRandom.size(); n++) {812if (addresses.size() >= nNodes)813break;815int nRndPos = insecure_rand.randrange(vRandom.size() - n) + n;816SwapRandom(n, nRndPos);817const auto it{mapInfo.find(vRandom[n])};818assert(it != mapInfo.end());820const AddrInfo& ai{it->second};822// Filter by network (optional)823if (network != std::nullopt && ai.GetNetClass() != network) continue;825// Filter for quality826if (ai.IsTerrible(now) && filtered) continue;828addresses.push_back(ai);829}830LogDebug(BCLog::ADDRMAN, "GetAddr returned %d random addresses\n", addresses.size());831return addresses;832}834std::vector<std::pair<AddrInfo, AddressPosition>> AddrManImpl::GetEntries_(bool from_tried) const835{836AssertLockHeld(cs);838const int bucket_count = from_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT;839std::vector<std::pair<AddrInfo, AddressPosition>> infos;840for (int bucket = 0; bucket < bucket_count; ++bucket) {841for (int position = 0; position < ADDRMAN_BUCKET_SIZE; ++position) {842nid_type id = GetEntry(from_tried, bucket, position);843if (id >= 0) {844AddrInfo info = mapInfo.at(id);845AddressPosition location = AddressPosition(846from_tried,847/*multiplicity_in=*/from_tried ? 1 : info.nRefCount,848bucket,849position);850infos.emplace_back(info, location);851}852}853}855return infos;856}858void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)859{860AssertLockHeld(cs);862AddrInfo* pinfo = Find(addr);864// if not found, bail out865if (!pinfo)866return;868AddrInfo& info = *pinfo;870// update info871const auto update_interval{20min};872if (time - info.nTime > update_interval) {873info.nTime = time;874}875}877void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)878{879AssertLockHeld(cs);881AddrInfo* pinfo = Find(addr);883// if not found, bail out884if (!pinfo)885return;887AddrInfo& info = *pinfo;889// update info890info.nServices = nServices;891}893void AddrManImpl::ResolveCollisions_()894{895AssertLockHeld(cs);897for (std::set<nid_type>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {898nid_type id_new = *it;900bool erase_collision = false;902// If id_new not found in mapInfo remove it from m_tried_collisions903if (!mapInfo.contains(id_new)) {904erase_collision = true;905} else {906AddrInfo& info_new = mapInfo[id_new];908// Which tried bucket to move the entry to.909int tried_bucket = info_new.GetTriedBucket(nKey, m_netgroupman);910int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);911if (!info_new.IsValid()) { // id_new may no longer map to a valid address912erase_collision = true;913} else {914// A pending tried collision implies that the destination tried slot915// remains occupied until we resolve it.916Assume(vvTried[tried_bucket][tried_bucket_pos] != -1);918// Get the to-be-evicted address that is being tested919nid_type id_old = vvTried[tried_bucket][tried_bucket_pos];920AddrInfo& info_old = mapInfo[id_old];922const auto current_time{Now<NodeSeconds>()};924// Has successfully connected in last X hours925if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {926erase_collision = true;927} else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours929// Give address at least 60 seconds to successfully connect930if (current_time - info_old.m_last_try > 60s) {931LogDebug(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());933// Replaces an existing address already in the tried table with the new address934Good_(info_new, false, current_time);935erase_collision = true;936}937} else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) {938// If the collision hasn't resolved in some reasonable amount of time,939// just evict the old entry -- we must not be able to940// connect to it for some reason.941LogDebug(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());942Good_(info_new, false, current_time);943erase_collision = true;944}945}946}948if (erase_collision) {949m_tried_collisions.erase(it++);950} else {951it++;952}953}954}956std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_()957{958AssertLockHeld(cs);960if (m_tried_collisions.size() == 0) return {};962std::set<nid_type>::iterator it = m_tried_collisions.begin();964// Selects a random element from m_tried_collisions965std::advance(it, insecure_rand.randrange(m_tried_collisions.size()));966nid_type id_new = *it;968// If id_new not found in mapInfo remove it from m_tried_collisions969if (!mapInfo.contains(id_new)) {970m_tried_collisions.erase(it);971return {};972}974const AddrInfo& newInfo = mapInfo[id_new];976// which tried bucket to move the entry to977int tried_bucket = newInfo.GetTriedBucket(nKey, m_netgroupman);978int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);980Assume(vvTried[tried_bucket][tried_bucket_pos] != -1);981const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];982return {info_old, info_old.m_last_try};983}985std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)986{987AssertLockHeld(cs);989AddrInfo* addr_info = Find(addr);991if (!addr_info) return std::nullopt;993if(addr_info->fInTried) {994int bucket{addr_info->GetTriedBucket(nKey, m_netgroupman)};995return AddressPosition(/*tried_in=*/true,996/*multiplicity_in=*/1,997/*bucket_in=*/bucket,998/*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket));999} else {1000int bucket{addr_info->GetNewBucket(nKey, m_netgroupman)};