Skip to content

Commit a65053f

Browse files
[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 <[email protected]>
1 parent 1622543 commit a65053f

File tree

2 files changed

+172
-166
lines changed

2 files changed

+172
-166
lines changed

src/addrman.cpp

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,181 @@ void CAddrMan::Serialize(Stream& s_) const
197197
s << asmap_checksum;
198198
}
199199

200+
template <typename Stream>
201+
void CAddrMan::Unserialize(Stream& s_)
202+
{
203+
LOCK(cs);
204+
205+
assert(vRandom.empty());
206+
207+
Format format;
208+
s_ >> Using<CustomUintFormatter<1>>(format);
209+
210+
int stream_version = s_.GetVersion();
211+
if (format >= Format::V3_BIP155) {
212+
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
213+
// unserialize methods know that an address in addrv2 format is coming.
214+
stream_version |= ADDRV2_FORMAT;
215+
}
216+
217+
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
218+
219+
uint8_t compat;
220+
s >> compat;
221+
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
222+
if (lowest_compatible > FILE_FORMAT) {
223+
throw std::ios_base::failure(strprintf(
224+
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
225+
"but the maximum supported by this version of %s is %u.",
226+
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
227+
}
228+
229+
s >> nKey;
230+
s >> nNew;
231+
s >> nTried;
232+
int nUBuckets = 0;
233+
s >> nUBuckets;
234+
if (format >= Format::V1_DETERMINISTIC) {
235+
nUBuckets ^= (1 << 30);
236+
}
237+
238+
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
239+
throw std::ios_base::failure(
240+
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
241+
nNew,
242+
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
243+
}
244+
245+
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
246+
throw std::ios_base::failure(
247+
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
248+
nTried,
249+
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
250+
}
251+
252+
// Deserialize entries from the new table.
253+
for (int n = 0; n < nNew; n++) {
254+
CAddrInfo &info = mapInfo[n];
255+
s >> info;
256+
mapAddr[info] = n;
257+
info.nRandomPos = vRandom.size();
258+
vRandom.push_back(n);
259+
}
260+
nIdCount = nNew;
261+
262+
// Deserialize entries from the tried table.
263+
int nLost = 0;
264+
for (int n = 0; n < nTried; n++) {
265+
CAddrInfo info;
266+
s >> info;
267+
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
268+
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
269+
if (info.IsValid()
270+
&& vvTried[nKBucket][nKBucketPos] == -1) {
271+
info.nRandomPos = vRandom.size();
272+
info.fInTried = true;
273+
vRandom.push_back(nIdCount);
274+
mapInfo[nIdCount] = info;
275+
mapAddr[info] = nIdCount;
276+
vvTried[nKBucket][nKBucketPos] = nIdCount;
277+
nIdCount++;
278+
} else {
279+
nLost++;
280+
}
281+
}
282+
nTried -= nLost;
283+
284+
// Store positions in the new table buckets to apply later (if possible).
285+
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
286+
// so we store all bucket-entry_index pairs to iterate through later.
287+
std::vector<std::pair<int, int>> bucket_entries;
288+
289+
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
290+
int num_entries{0};
291+
s >> num_entries;
292+
for (int n = 0; n < num_entries; ++n) {
293+
int entry_index{0};
294+
s >> entry_index;
295+
if (entry_index >= 0 && entry_index < nNew) {
296+
bucket_entries.emplace_back(bucket, entry_index);
297+
}
298+
}
299+
}
300+
301+
// If the bucket count and asmap checksum haven't changed, then attempt
302+
// to restore the entries to the buckets/positions they were in before
303+
// serialization.
304+
uint256 supplied_asmap_checksum;
305+
if (m_asmap.size() != 0) {
306+
supplied_asmap_checksum = SerializeHash(m_asmap);
307+
}
308+
uint256 serialized_asmap_checksum;
309+
if (format >= Format::V2_ASMAP) {
310+
s >> serialized_asmap_checksum;
311+
}
312+
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
313+
serialized_asmap_checksum == supplied_asmap_checksum};
314+
315+
if (!restore_bucketing) {
316+
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
317+
}
318+
319+
for (auto bucket_entry : bucket_entries) {
320+
int bucket{bucket_entry.first};
321+
const int entry_index{bucket_entry.second};
322+
CAddrInfo& info = mapInfo[entry_index];
323+
324+
// Don't store the entry in the new bucket if it's not a valid address for our addrman
325+
if (!info.IsValid()) continue;
326+
327+
// The entry shouldn't appear in more than
328+
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
329+
// this bucket_entry.
330+
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
331+
332+
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
333+
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
334+
// Bucketing has not changed, using existing bucket positions for the new table
335+
vvNew[bucket][bucket_position] = entry_index;
336+
++info.nRefCount;
337+
} else {
338+
// In case the new table data cannot be used (bucket count wrong or new asmap),
339+
// try to give them a reference based on their primary source address.
340+
bucket = info.GetNewBucket(nKey, m_asmap);
341+
bucket_position = info.GetBucketPosition(nKey, true, bucket);
342+
if (vvNew[bucket][bucket_position] == -1) {
343+
vvNew[bucket][bucket_position] = entry_index;
344+
++info.nRefCount;
345+
}
346+
}
347+
}
348+
349+
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
350+
int nLostUnk = 0;
351+
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
352+
if (it->second.fInTried == false && it->second.nRefCount == 0) {
353+
const auto itCopy = it++;
354+
Delete(itCopy->first);
355+
++nLostUnk;
356+
} else {
357+
++it;
358+
}
359+
}
360+
if (nLost + nLostUnk > 0) {
361+
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
362+
}
363+
364+
Check();
365+
}
366+
200367
// explicit instantiation
201368
template void CAddrMan::Serialize(CHashWriter& s) const;
202369
template void CAddrMan::Serialize(CAutoFile& s) const;
203370
template void CAddrMan::Serialize(CDataStream& s) const;
371+
template void CAddrMan::Unserialize(CAutoFile& s);
372+
template void CAddrMan::Unserialize(CHashVerifier<CAutoFile>& s);
373+
template void CAddrMan::Unserialize(CDataStream& s);
374+
template void CAddrMan::Unserialize(CHashVerifier<CDataStream>& s);
204375

205376
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
206377
{

src/addrman.h

Lines changed: 1 addition & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -204,172 +204,7 @@ class CAddrMan
204204
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
205205

206206
template <typename Stream>
207-
void Unserialize(Stream& s_)
208-
EXCLUSIVE_LOCKS_REQUIRED(!cs)
209-
{
210-
LOCK(cs);
211-
212-
assert(vRandom.empty());
213-
214-
Format format;
215-
s_ >> Using<CustomUintFormatter<1>>(format);
216-
217-
int stream_version = s_.GetVersion();
218-
if (format >= Format::V3_BIP155) {
219-
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
220-
// unserialize methods know that an address in addrv2 format is coming.
221-
stream_version |= ADDRV2_FORMAT;
222-
}
223-
224-
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
225-
226-
uint8_t compat;
227-
s >> compat;
228-
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
229-
if (lowest_compatible > FILE_FORMAT) {
230-
throw std::ios_base::failure(strprintf(
231-
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
232-
"but the maximum supported by this version of %s is %u.",
233-
format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT)));
234-
}
235-
236-
s >> nKey;
237-
s >> nNew;
238-
s >> nTried;
239-
int nUBuckets = 0;
240-
s >> nUBuckets;
241-
if (format >= Format::V1_DETERMINISTIC) {
242-
nUBuckets ^= (1 << 30);
243-
}
244-
245-
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nNew < 0) {
246-
throw std::ios_base::failure(
247-
strprintf("Corrupt CAddrMan serialization: nNew=%d, should be in [0, %u]",
248-
nNew,
249-
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
250-
}
251-
252-
if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE || nTried < 0) {
253-
throw std::ios_base::failure(
254-
strprintf("Corrupt CAddrMan serialization: nTried=%d, should be in [0, %u]",
255-
nTried,
256-
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE));
257-
}
258-
259-
// Deserialize entries from the new table.
260-
for (int n = 0; n < nNew; n++) {
261-
CAddrInfo &info = mapInfo[n];
262-
s >> info;
263-
mapAddr[info] = n;
264-
info.nRandomPos = vRandom.size();
265-
vRandom.push_back(n);
266-
}
267-
nIdCount = nNew;
268-
269-
// Deserialize entries from the tried table.
270-
int nLost = 0;
271-
for (int n = 0; n < nTried; n++) {
272-
CAddrInfo info;
273-
s >> info;
274-
int nKBucket = info.GetTriedBucket(nKey, m_asmap);
275-
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
276-
if (info.IsValid()
277-
&& vvTried[nKBucket][nKBucketPos] == -1) {
278-
info.nRandomPos = vRandom.size();
279-
info.fInTried = true;
280-
vRandom.push_back(nIdCount);
281-
mapInfo[nIdCount] = info;
282-
mapAddr[info] = nIdCount;
283-
vvTried[nKBucket][nKBucketPos] = nIdCount;
284-
nIdCount++;
285-
} else {
286-
nLost++;
287-
}
288-
}
289-
nTried -= nLost;
290-
291-
// Store positions in the new table buckets to apply later (if possible).
292-
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
293-
// so we store all bucket-entry_index pairs to iterate through later.
294-
std::vector<std::pair<int, int>> bucket_entries;
295-
296-
for (int bucket = 0; bucket < nUBuckets; ++bucket) {
297-
int num_entries{0};
298-
s >> num_entries;
299-
for (int n = 0; n < num_entries; ++n) {
300-
int entry_index{0};
301-
s >> entry_index;
302-
if (entry_index >= 0 && entry_index < nNew) {
303-
bucket_entries.emplace_back(bucket, entry_index);
304-
}
305-
}
306-
}
307-
308-
// If the bucket count and asmap checksum haven't changed, then attempt
309-
// to restore the entries to the buckets/positions they were in before
310-
// serialization.
311-
uint256 supplied_asmap_checksum;
312-
if (m_asmap.size() != 0) {
313-
supplied_asmap_checksum = SerializeHash(m_asmap);
314-
}
315-
uint256 serialized_asmap_checksum;
316-
if (format >= Format::V2_ASMAP) {
317-
s >> serialized_asmap_checksum;
318-
}
319-
const bool restore_bucketing{nUBuckets == ADDRMAN_NEW_BUCKET_COUNT &&
320-
serialized_asmap_checksum == supplied_asmap_checksum};
321-
322-
if (!restore_bucketing) {
323-
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
324-
}
325-
326-
for (auto bucket_entry : bucket_entries) {
327-
int bucket{bucket_entry.first};
328-
const int entry_index{bucket_entry.second};
329-
CAddrInfo& info = mapInfo[entry_index];
330-
331-
// Don't store the entry in the new bucket if it's not a valid address for our addrman
332-
if (!info.IsValid()) continue;
333-
334-
// The entry shouldn't appear in more than
335-
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
336-
// this bucket_entry.
337-
if (info.nRefCount >= ADDRMAN_NEW_BUCKETS_PER_ADDRESS) continue;
338-
339-
int bucket_position = info.GetBucketPosition(nKey, true, bucket);
340-
if (restore_bucketing && vvNew[bucket][bucket_position] == -1) {
341-
// Bucketing has not changed, using existing bucket positions for the new table
342-
vvNew[bucket][bucket_position] = entry_index;
343-
++info.nRefCount;
344-
} else {
345-
// In case the new table data cannot be used (bucket count wrong or new asmap),
346-
// try to give them a reference based on their primary source address.
347-
bucket = info.GetNewBucket(nKey, m_asmap);
348-
bucket_position = info.GetBucketPosition(nKey, true, bucket);
349-
if (vvNew[bucket][bucket_position] == -1) {
350-
vvNew[bucket][bucket_position] = entry_index;
351-
++info.nRefCount;
352-
}
353-
}
354-
}
355-
356-
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
357-
int nLostUnk = 0;
358-
for (auto it = mapInfo.cbegin(); it != mapInfo.cend(); ) {
359-
if (it->second.fInTried == false && it->second.nRefCount == 0) {
360-
const auto itCopy = it++;
361-
Delete(itCopy->first);
362-
++nLostUnk;
363-
} else {
364-
++it;
365-
}
366-
}
367-
if (nLost + nLostUnk > 0) {
368-
LogPrint(BCLog::ADDRMAN, "addrman lost %i new and %i tried addresses due to collisions or invalid addresses\n", nLostUnk, nLost);
369-
}
370-
371-
Check();
372-
}
207+
void Unserialize(Stream& s_) EXCLUSIVE_LOCKS_REQUIRED(!cs);
373208

374209
explicit CAddrMan(bool deterministic, int32_t consistency_check_ratio);
375210

0 commit comments

Comments
 (0)