Changeset View
Changeset View
Standalone View
Standalone View
src/addrman.cpp
// Copyright (c) 2012 Pieter Wuille | // Copyright (c) 2012 Pieter Wuille | ||||
// Copyright (c) 2012-2016 The Bitcoin Core developers | // Copyright (c) 2012-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <addrman.h> | #include <addrman.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <serialize.h> | #include <serialize.h> | ||||
#include <cmath> | #include <cmath> | ||||
int CAddrInfo::GetTriedBucket(const uint256 &nKey) const { | int CAddrInfo::GetTriedBucket(const uint256 &nKey, | ||||
const std::vector<bool> &asmap) const { | |||||
uint64_t hash1 = | uint64_t hash1 = | ||||
(CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash(); | (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash(); | ||||
uint64_t hash2 = | uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) | ||||
(CHashWriter(SER_GETHASH, 0) | << nKey << GetGroup(asmap) | ||||
<< nKey << GetGroup() << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)) | << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)) | ||||
.GetCheapHash(); | .GetCheapHash(); | ||||
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; | return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; | ||||
} | } | ||||
int CAddrInfo::GetNewBucket(const uint256 &nKey, const CNetAddr &src) const { | int CAddrInfo::GetNewBucket(const uint256 &nKey, const CNetAddr &src, | ||||
std::vector<uint8_t> vchSourceGroupKey = src.GetGroup(); | const std::vector<bool> &asmap) const { | ||||
uint64_t hash1 = | std::vector<uint8_t> vchSourceGroupKey = src.GetGroup(asmap); | ||||
(CHashWriter(SER_GETHASH, 0) << nKey << GetGroup() << vchSourceGroupKey) | uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) | ||||
<< nKey << GetGroup(asmap) << vchSourceGroupKey) | |||||
.GetCheapHash(); | .GetCheapHash(); | ||||
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) | uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) | ||||
<< nKey << vchSourceGroupKey | << nKey << vchSourceGroupKey | ||||
<< (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)) | << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)) | ||||
.GetCheapHash(); | .GetCheapHash(); | ||||
return hash2 % ADDRMAN_NEW_BUCKET_COUNT; | return hash2 % ADDRMAN_NEW_BUCKET_COUNT; | ||||
} | } | ||||
int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, | int CAddrInfo::GetBucketPosition(const uint256 &nKey, bool fNew, | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { | ||||
info.nRefCount--; | info.nRefCount--; | ||||
} | } | ||||
} | } | ||||
nNew--; | nNew--; | ||||
assert(info.nRefCount == 0); | assert(info.nRefCount == 0); | ||||
// which tried bucket to move the entry to | // which tried bucket to move the entry to | ||||
int nKBucket = info.GetTriedBucket(nKey); | int nKBucket = info.GetTriedBucket(nKey, m_asmap); | ||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); | int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); | ||||
// first make space to add it (the existing tried entry there is moved to | // first make space to add it (the existing tried entry there is moved to | ||||
// new, deleting whatever is there). | // new, deleting whatever is there). | ||||
if (vvTried[nKBucket][nKBucketPos] != -1) { | if (vvTried[nKBucket][nKBucketPos] != -1) { | ||||
// find an item to evict | // find an item to evict | ||||
int nIdEvict = vvTried[nKBucket][nKBucketPos]; | int nIdEvict = vvTried[nKBucket][nKBucketPos]; | ||||
assert(mapInfo.count(nIdEvict) == 1); | assert(mapInfo.count(nIdEvict) == 1); | ||||
CAddrInfo &infoOld = mapInfo[nIdEvict]; | CAddrInfo &infoOld = mapInfo[nIdEvict]; | ||||
// Remove the to-be-evicted item from the tried set. | // Remove the to-be-evicted item from the tried set. | ||||
infoOld.fInTried = false; | infoOld.fInTried = false; | ||||
vvTried[nKBucket][nKBucketPos] = -1; | vvTried[nKBucket][nKBucketPos] = -1; | ||||
nTried--; | nTried--; | ||||
// find which new bucket it belongs to | // find which new bucket it belongs to | ||||
int nUBucket = infoOld.GetNewBucket(nKey); | int nUBucket = infoOld.GetNewBucket(nKey, m_asmap); | ||||
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket); | int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket); | ||||
ClearNew(nUBucket, nUBucketPos); | ClearNew(nUBucket, nUBucketPos); | ||||
assert(vvNew[nUBucket][nUBucketPos] == -1); | assert(vvNew[nUBucket][nUBucketPos] == -1); | ||||
// Enter it into the new set again. | // Enter it into the new set again. | ||||
infoOld.nRefCount = 1; | infoOld.nRefCount = 1; | ||||
vvNew[nUBucket][nUBucketPos] = nIdEvict; | vvNew[nUBucket][nUBucketPos] = nIdEvict; | ||||
nNew++; | nNew++; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | void CAddrMan::Good_(const CService &addr, bool test_before_evict, | ||||
// if no bucket is found, something bad happened; | // if no bucket is found, something bad happened; | ||||
// TODO: maybe re-add the node, but for now, just bail out | // TODO: maybe re-add the node, but for now, just bail out | ||||
if (nUBucket == -1) { | if (nUBucket == -1) { | ||||
return; | return; | ||||
} | } | ||||
// which tried bucket to move the entry to | // which tried bucket to move the entry to | ||||
int tried_bucket = info.GetTriedBucket(nKey); | int tried_bucket = info.GetTriedBucket(nKey, m_asmap); | ||||
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket); | int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket); | ||||
// Will moving this address into tried evict another entry? | // Will moving this address into tried evict another entry? | ||||
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) { | if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) { | ||||
// Output the entry we'd be colliding with, for debugging purposes | // Output the entry we'd be colliding with, for debugging purposes | ||||
auto colliding_entry = | auto colliding_entry = | ||||
mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]); | mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]); | ||||
LogPrint(BCLog::ADDRMAN, | LogPrint(BCLog::ADDRMAN, | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | bool CAddrMan::Add_(const CAddress &addr, const CNetAddr &source, | ||||
} else { | } else { | ||||
pinfo = Create(addr, source, &nId); | pinfo = Create(addr, source, &nId); | ||||
pinfo->nTime = | pinfo->nTime = | ||||
std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); | std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); | ||||
nNew++; | nNew++; | ||||
fNew = true; | fNew = true; | ||||
} | } | ||||
int nUBucket = pinfo->GetNewBucket(nKey, source); | int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap); | ||||
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); | int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); | ||||
if (vvNew[nUBucket][nUBucketPos] != nId) { | if (vvNew[nUBucket][nUBucketPos] != nId) { | ||||
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; | bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; | ||||
if (!fInsert) { | if (!fInsert) { | ||||
CAddrInfo &infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; | CAddrInfo &infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; | ||||
if (infoExisting.IsTerrible() || | if (infoExisting.IsTerrible() || | ||||
(infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { | (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { | ||||
// Overwrite the existing new table entry. | // Overwrite the existing new table entry. | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | int CAddrMan::Check_() { | ||||
} | } | ||||
for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) { | for (int n = 0; n < ADDRMAN_TRIED_BUCKET_COUNT; n++) { | ||||
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { | ||||
if (vvTried[n][i] != -1) { | if (vvTried[n][i] != -1) { | ||||
if (!setTried.count(vvTried[n][i])) { | if (!setTried.count(vvTried[n][i])) { | ||||
return -11; | return -11; | ||||
} | } | ||||
if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey) != n) { | if (mapInfo[vvTried[n][i]].GetTriedBucket(nKey, m_asmap) != n) { | ||||
return -17; | return -17; | ||||
} | } | ||||
if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != | if (mapInfo[vvTried[n][i]].GetBucketPosition(nKey, false, n) != | ||||
i) { | i) { | ||||
return -18; | return -18; | ||||
} | } | ||||
setTried.erase(vvTried[n][i]); | setTried.erase(vvTried[n][i]); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | for (std::set<int>::iterator it = m_tried_collisions.begin(); | ||||
// If id_new not found in mapInfo remove it from m_tried_collisions. | // If id_new not found in mapInfo remove it from m_tried_collisions. | ||||
auto id_new_it = mapInfo.find(id_new); | auto id_new_it = mapInfo.find(id_new); | ||||
if (id_new_it == mapInfo.end()) { | if (id_new_it == mapInfo.end()) { | ||||
erase_collision = true; | erase_collision = true; | ||||
} else { | } else { | ||||
CAddrInfo &info_new = id_new_it->second; | CAddrInfo &info_new = id_new_it->second; | ||||
// Which tried bucket to move the entry to. | // Which tried bucket to move the entry to. | ||||
int tried_bucket = info_new.GetTriedBucket(nKey); | int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap); | ||||
int tried_bucket_pos = | int tried_bucket_pos = | ||||
info_new.GetBucketPosition(nKey, false, tried_bucket); | info_new.GetBucketPosition(nKey, false, tried_bucket); | ||||
if (!info_new.IsValid()) { | if (!info_new.IsValid()) { | ||||
// id_new may no longer map to a valid address | // id_new may no longer map to a valid address | ||||
erase_collision = true; | erase_collision = true; | ||||
} else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { | } else if (vvTried[tried_bucket][tried_bucket_pos] != -1) { | ||||
// The position in the tried bucket is not empty | // The position in the tried bucket is not empty | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | CAddrInfo CAddrMan::SelectTriedCollision_() { | ||||
if (id_new_it == mapInfo.end()) { | if (id_new_it == mapInfo.end()) { | ||||
m_tried_collisions.erase(it); | m_tried_collisions.erase(it); | ||||
return CAddrInfo(); | return CAddrInfo(); | ||||
} | } | ||||
CAddrInfo &newInfo = id_new_it->second; | CAddrInfo &newInfo = id_new_it->second; | ||||
// which tried bucket to move the entry to | // which tried bucket to move the entry to | ||||
int tried_bucket = newInfo.GetTriedBucket(nKey); | int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap); | ||||
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket); | int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket); | ||||
int id_old = vvTried[tried_bucket][tried_bucket_pos]; | int id_old = vvTried[tried_bucket][tried_bucket_pos]; | ||||
return mapInfo[id_old]; | return mapInfo[id_old]; | ||||
} | } | ||||
std::vector<bool> CAddrMan::DecodeAsmap(fs::path path) { | |||||
std::vector<bool> bits; | |||||
FILE *filestr = fsbridge::fopen(path, "rb"); | |||||
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION); | |||||
if (file.IsNull()) { | |||||
LogPrintf("Failed to open asmap file from disk.\n"); | |||||
return bits; | |||||
} | |||||
fseek(filestr, 0, SEEK_END); | |||||
int length = ftell(filestr); | |||||
LogPrintf("Opened asmap file %s (%d bytes) from disk.\n", path, length); | |||||
fseek(filestr, 0, SEEK_SET); | |||||
char cur_byte; | |||||
for (int i = 0; i < length; ++i) { | |||||
file >> cur_byte; | |||||
for (int bit = 0; bit < 8; ++bit) { | |||||
bits.push_back((cur_byte >> bit) & 1); | |||||
} | |||||
} | |||||
return bits; | |||||
} |