@@ -197,10 +197,181 @@ void CAddrMan::Serialize(Stream& s_) const
197
197
s << asmap_checksum;
198
198
}
199
199
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
+
200
367
// explicit instantiation
201
368
template void CAddrMan::Serialize (CHashWriter& s) const ;
202
369
template void CAddrMan::Serialize (CAutoFile& s) const ;
203
370
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);
204
375
205
376
CAddrInfo* CAddrMan::Find (const CNetAddr& addr, int * pnId)
206
377
{
0 commit comments