mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
[addrman] Move CAddrMan::Unserialize to cpp file
Reviewer hint: use `git diff --color-moved=dimmed-zebra --color-moved-ws=ignore-all-space` Co-authored-by: Amiti Uttarwar <amiti@uttarwar.org>
This commit is contained in:
parent
1622543cf4
commit
a65053f1d4
2 changed files with 172 additions and 166 deletions
171
src/addrman.cpp
171
src/addrman.cpp
|
@ -197,10 +197,181 @@ void CAddrMan::Serialize(Stream& s_) const
|
|||
s << asmap_checksum;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void CAddrMan::Unserialize(Stream& s_)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
assert(vRandom.empty());
|
||||
|
||||
Format format;
|
||||
s_ >> Using<CustomUintFormatter<1>>(format);
|
||||
|
||||
int stream_version = s_.GetVersion();
|
||||
if (format >= Format::V3_BIP155) {
|
||||
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
|
||||
// unserialize methods know that an address in addrv2 format is coming.
|
||||
stream_version |= ADDRV2_FORMAT;
|
||||
}
|
||||
|
||||
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
|
||||
|
||||
uint8_t compat;
|
||||
s >> compat;
|
||||
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
|
||||
if (lowest_compatible > FILE_FORMAT) {
|
||||
throw std::ios_base::failure(strprintf(
|
||||
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
|
||||
"but the maximum supported by this version of %s is %u.",
|
||||
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
|
||||
}
|
||||
|
||||
s >> nKey;
|
||||
s >> nNew;
|
||||
s >> nTried;
|
||||
int nUBuckets = 0;
|
||||
s >> nUBuckets;
|
||||
if (format >= Format::V1_DETERMINISTIC) {
|
||||
nUBuckets ^= (1 << 30);
|
||||
}
|
||||
|
||||
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
|
||||
nNew,
|
||||
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
|
||||
nTried,
|
||||
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
// Deserialize entries from the new table.
|
||||
for (int n = 0; n < nNew; n++) {
|
||||
CAddrInfo &info = mapInfo[n];
|
||||
s >> info;
|
||||
mapAddr[info] = n;
|
||||
info.nRandomPos = vRandom.size();
|
||||
vRandom.push_back(n);
|
||||
}
|
||||
nIdCount = nNew;
|
||||
|
||||
// Deserialize entries from the tried table.
|
||||
int nLost = 0;
|
||||
for (int n = 0; n < nTried; n++) {
|
||||
CAddrInfo info;
|
||||
s >> info;
|
||||
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
||||
if (info.IsValid()
|
||||
&& vvTried[nKBucket][nKBucketPos] == -1) {
|
||||
info.nRandomPos = vRandom.size();
|
||||
info.fInTried = true;
|
||||
vRandom.push_back(nIdCount);
|
||||
mapInfo[nIdCount] = info;
|
||||
mapAddr[info] = nIdCount;
|
||||
vvTried[nKBucket][nKBucketPos] = nIdCount;
|
||||
nIdCount++;
|
||||
} else {
|
||||
nLost++;
|
||||
}
|
||||
}
|
||||
nTried -= nLost;
|
||||
|
||||
// Store positions in the new table buckets to apply later (if possible).
|
||||
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
|
||||
// so we store all bucket-entry_index pairs to iterate through later.
|
||||
std::vector<std::pair<int, int>> bucket_entries;
|
||||
|
||||
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
|
||||
int num_entries{0};
|
||||
s >> num_entries;
|
||||
for (int n = 0; n < num_entries; ++n) {
|
||||
int entry_index{0};
|
||||
s >> entry_index;
|
||||
if (entry_index >= 0 && entry_index < nNew) {
|
||||
bucket_entries.emplace_back(bucket, entry_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the bucket count and asmap checksum haven't changed, then attempt
|
||||
// to restore the entries to the buckets/positions they were in before
|
||||
// serialization.
|
||||
uint256 supplied_asmap_checksum;
|
||||
if (m_asmap.size() != 0) {
|
||||
supplied_asmap_checksum = SerializeHash(m_asmap);
|
||||
}
|
||||
uint256 serialized_asmap_checksum;
|
||||
if (format >= Format::V2_ASMAP) {
|
||||
s >> serialized_asmap_checksum;
|
||||
}
|
||||
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
|
||||
serialized_asmap_checksum == supplied_asmap_checksum};
|
||||
|
||||
if (!restore_bucketing) {
|
||||
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
|
||||
}
|
||||
|
||||
for (auto bucket_entry : bucket_entries) {
|
||||
int bucket{bucket_entry.first};
|
||||
const int entry_index{bucket_entry.second};
|
||||
CAddrInfo& info = mapInfo[entry_index];
|
||||
|
||||
// Don't store the entry in the new bucket if it's not a valid address for our addrman
|
||||
if (!info.IsValid()) continue;
|
||||
|
||||
// The entry shouldn't appear in more than
|
||||
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
|
||||
// this bucket_entry.
|
||||
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
|
||||
|
||||
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
|
||||
// Bucketing has not changed, using existing bucket positions for the new table
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
} else {
|
||||
// In case the new table data cannot be used (bucket count wrong or new asmap),
|
||||
// try to give them a reference based on their primary source address.
|
||||
bucket = info.GetNewBucket(nKey, m_asmap);
|
||||
bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (vvNew[bucket][bucket_position] == -1) {
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
|
||||
int nLostUnk = 0;
|
||||
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
|
||||
if (it->second.fInTried == false && it->second.nRefCount == 0) {
|
||||
const auto itCopy = it++;
|
||||
Delete(itCopy->first);
|
||||
++nLostUnk;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (nLost + nLostUnk > 0) {
|
||||
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
|
||||
}
|
||||
|
||||
Check();
|
||||
}
|
||||
|
||||
// explicit instantiation
|
||||
template void CAddrMan::Serialize(CHashWriter& s) const;
|
||||
template void CAddrMan::Serialize(CAutoFile& s) const;
|
||||
template void CAddrMan::Serialize(CDataStream& s) const;
|
||||
template void CAddrMan::Unserialize(CAutoFile& s);
|
||||
template void CAddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
|
||||
template void CAddrMan::Unserialize(CDataStream& s);
|
||||
template void CAddrMan::Unserialize(CHashVerifier<CDataStream>& s);
|
||||
|
||||
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
|
||||
{
|
||||
|
|
167
src/addrman.h
167
src/addrman.h
|
@ -204,172 +204,7 @@ public:
|
|||
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& s_)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(!cs)
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
assert(vRandom.empty());
|
||||
|
||||
Format format;
|
||||
s_ >> Using<CustomUintFormatter<1>>(format);
|
||||
|
||||
int stream_version = s_.GetVersion();
|
||||
if (format >= Format::V3_BIP155) {
|
||||
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
|
||||
// unserialize methods know that an address in addrv2 format is coming.
|
||||
stream_version |= ADDRV2_FORMAT;
|
||||
}
|
||||
|
||||
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
|
||||
|
||||
uint8_t compat;
|
||||
s >> compat;
|
||||
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
|
||||
if (lowest_compatible > FILE_FORMAT) {
|
||||
throw std::ios_base::failure(strprintf(
|
||||
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
|
||||
"but the maximum supported by this version of %s is %u.",
|
||||
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
|
||||
}
|
||||
|
||||
s >> nKey;
|
||||
s >> nNew;
|
||||
s >> nTried;
|
||||
int nUBuckets = 0;
|
||||
s >> nUBuckets;
|
||||
if (format >= Format::V1_DETERMINISTIC) {
|
||||
nUBuckets ^= (1 << 30);
|
||||
}
|
||||
|
||||
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
|
||||
nNew,
|
||||
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
|
||||
throw std::ios_base::failure(
|
||||
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
|
||||
nTried,
|
||||
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
|
||||
}
|
||||
|
||||
// Deserialize entries from the new table.
|
||||
for (int n = 0; n < nNew; n++) {
|
||||
CAddrInfo &info = mapInfo[n];
|
||||
s >> info;
|
||||
mapAddr[info] = n;
|
||||
info.nRandomPos = vRandom.size();
|
||||
vRandom.push_back(n);
|
||||
}
|
||||
nIdCount = nNew;
|
||||
|
||||
// Deserialize entries from the tried table.
|
||||
int nLost = 0;
|
||||
for (int n = 0; n < nTried; n++) {
|
||||
CAddrInfo info;
|
||||
s >> info;
|
||||
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
|
||||
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
|
||||
if (info.IsValid()
|
||||
&& vvTried[nKBucket][nKBucketPos] == -1) {
|
||||
info.nRandomPos = vRandom.size();
|
||||
info.fInTried = true;
|
||||
vRandom.push_back(nIdCount);
|
||||
mapInfo[nIdCount] = info;
|
||||
mapAddr[info] = nIdCount;
|
||||
vvTried[nKBucket][nKBucketPos] = nIdCount;
|
||||
nIdCount++;
|
||||
} else {
|
||||
nLost++;
|
||||
}
|
||||
}
|
||||
nTried -= nLost;
|
||||
|
||||
// Store positions in the new table buckets to apply later (if possible).
|
||||
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
|
||||
// so we store all bucket-entry_index pairs to iterate through later.
|
||||
std::vector<std::pair<int, int>> bucket_entries;
|
||||
|
||||
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
|
||||
int num_entries{0};
|
||||
s >> num_entries;
|
||||
for (int n = 0; n < num_entries; ++n) {
|
||||
int entry_index{0};
|
||||
s >> entry_index;
|
||||
if (entry_index >= 0 && entry_index < nNew) {
|
||||
bucket_entries.emplace_back(bucket, entry_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the bucket count and asmap checksum haven't changed, then attempt
|
||||
// to restore the entries to the buckets/positions they were in before
|
||||
// serialization.
|
||||
uint256 supplied_asmap_checksum;
|
||||
if (m_asmap.size() != 0) {
|
||||
supplied_asmap_checksum = SerializeHash(m_asmap);
|
||||
}
|
||||
uint256 serialized_asmap_checksum;
|
||||
if (format >= Format::V2_ASMAP) {
|
||||
s >> serialized_asmap_checksum;
|
||||
}
|
||||
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
|
||||
serialized_asmap_checksum == supplied_asmap_checksum};
|
||||
|
||||
if (!restore_bucketing) {
|
||||
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
|
||||
}
|
||||
|
||||
for (auto bucket_entry : bucket_entries) {
|
||||
int bucket{bucket_entry.first};
|
||||
const int entry_index{bucket_entry.second};
|
||||
CAddrInfo& info = mapInfo[entry_index];
|
||||
|
||||
// Don't store the entry in the new bucket if it's not a valid address for our addrman
|
||||
if (!info.IsValid()) continue;
|
||||
|
||||
// The entry shouldn't appear in more than
|
||||
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
|
||||
// this bucket_entry.
|
||||
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
|
||||
|
||||
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
|
||||
// Bucketing has not changed, using existing bucket positions for the new table
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
} else {
|
||||
// In case the new table data cannot be used (bucket count wrong or new asmap),
|
||||
// try to give them a reference based on their primary source address.
|
||||
bucket = info.GetNewBucket(nKey, m_asmap);
|
||||
bucket_position = info.GetBucketPosition(nKey, true, bucket);
|
||||
if (vvNew[bucket][bucket_position] == -1) {
|
||||
vvNew[bucket][bucket_position] = entry_index;
|
||||
++info.nRefCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
|
||||
int nLostUnk = 0;
|
||||
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
|
||||
if (it->second.fInTried == false && it->second.nRefCount == 0) {
|
||||
const auto itCopy = it++;
|
||||
Delete(itCopy->first);
|
||||
++nLostUnk;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (nLost + nLostUnk > 0) {
|
||||
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
|
||||
}
|
||||
|
||||
Check();
|
||||
}
|
||||
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
|
||||
|
||||
explicit CAddrMan(bool deterministic, int32_t consistency_check_ratio);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue