7
7
#define BITCOIN_ADDRMAN_H
8
8
9
9
#include < clientversion.h>
10
+ #include < config/bitcoin-config.h>
10
11
#include < netaddress.h>
11
12
#include < protocol.h>
12
13
#include < random.h>
@@ -176,6 +177,28 @@ friend class CAddrManTest;
176
177
mutable RecursiveMutex cs;
177
178
178
179
private:
180
+ // ! Serialization versions.
181
+ enum Format : uint8_t {
182
+ V0_HISTORICAL = 0 , // !< historic format, before commit e6b343d88
183
+ V1_DETERMINISTIC = 1 , // !< for pre-asmap files
184
+ V2_ASMAP = 2 , // !< for files including asmap version
185
+ V3_BIP155 = 3 , // !< same as V2_ASMAP plus addresses are in BIP155 format
186
+ };
187
+
188
+ // ! The maximum format this software knows it can unserialize. Also, we always serialize
189
+ // ! in this format.
190
+ // ! The format (first byte in the serialized stream) can be higher than this and
191
+ // ! still this software may be able to unserialize the file - if the second byte
192
+ // ! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
193
+ static constexpr Format FILE_FORMAT = Format::V3_BIP155;
194
+
195
+ // ! The initial value of a field that is incremented every time an incompatible format
196
+ // ! change is made (such that old software versions would not be able to parse and
197
+ // ! understand the new file format). This is 32 because we overtook the "key size"
198
+ // ! field which was 32 historically.
199
+ // ! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
200
+ static constexpr uint8_t INCOMPATIBILITY_BASE = 32 ;
201
+
179
202
// ! last used nId
180
203
int nIdCount GUARDED_BY (cs);
181
204
@@ -265,14 +288,6 @@ friend class CAddrManTest;
265
288
void SetServices_ (const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
266
289
267
290
public:
268
- // ! Serialization versions.
269
- enum class Format : uint8_t {
270
- V0_HISTORICAL = 0 , // !< historic format, before commit e6b343d88
271
- V1_DETERMINISTIC = 1 , // !< for pre-asmap files
272
- V2_ASMAP = 2 , // !< for files including asmap version
273
- V3_BIP155 = 3 , // !< same as V2_ASMAP plus addresses are in BIP155 format
274
- };
275
-
276
291
// Compressed IP->ASN mapping, loaded from a file when a node starts.
277
292
// Should be always empty if no file was provided.
278
293
// This mapping is then used for bucketing nodes in Addrman.
@@ -295,8 +310,18 @@ friend class CAddrManTest;
295
310
296
311
/* *
297
312
* Serialized format.
298
- * * version byte (@see `Format`)
299
- * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
313
+ * * format version byte (@see `Format`)
314
+ * * lowest compatible format version byte. This is used to help old software decide
315
+ * whether to parse the file. For example:
316
+ * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
317
+ * introduced in version N+1 that is compatible with format=3 and it is known that
318
+ * version N will be able to parse it, then version N+1 will write
319
+ * (format=4, lowest_compatible=3) in the first two bytes of the file, and so
320
+ * version N will still try to parse it.
321
+ * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
322
+ * (format=5, lowest_compatible=5) and so any versions that do not know how to parse
323
+ * format=5 will not try to read the file.
324
+ * * nKey
300
325
* * nNew
301
326
* * nTried
302
327
* * number of "new" buckets XOR 2**30
@@ -327,12 +352,17 @@ friend class CAddrManTest;
327
352
{
328
353
LOCK (cs);
329
354
330
- // Always serialize in the latest version (currently Format::V3_BIP155 ).
355
+ // Always serialize in the latest version (FILE_FORMAT ).
331
356
332
357
OverrideStream<Stream> s (&s_, s_.GetType (), s_.GetVersion () | ADDRV2_FORMAT);
333
358
334
- s << static_cast <uint8_t >(Format::V3_BIP155);
335
- s << ((unsigned char )32 );
359
+ s << static_cast <uint8_t >(FILE_FORMAT);
360
+
361
+ // Increment `lowest_compatible` iff a newly introduced format is incompatible with
362
+ // the previous one.
363
+ static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
364
+ s << static_cast <uint8_t >(INCOMPATIBILITY_BASE + lowest_compatible);
365
+
336
366
s << nKey;
337
367
s << nNew;
338
368
s << nTried;
@@ -392,15 +422,6 @@ friend class CAddrManTest;
392
422
Format format;
393
423
s_ >> Using<CustomUintFormatter<1 >>(format);
394
424
395
- static constexpr Format maximum_supported_format = Format::V3_BIP155;
396
- if (format > maximum_supported_format) {
397
- throw std::ios_base::failure (strprintf (
398
- " Unsupported format of addrman database: %u. Maximum supported is %u. "
399
- " Continuing operation without using the saved list of peers." ,
400
- static_cast <uint8_t >(format),
401
- static_cast <uint8_t >(maximum_supported_format)));
402
- }
403
-
404
425
int stream_version = s_.GetVersion ();
405
426
if (format >= Format::V3_BIP155) {
406
427
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
@@ -410,9 +431,16 @@ friend class CAddrManTest;
410
431
411
432
OverrideStream<Stream> s (&s_, s_.GetType (), stream_version);
412
433
413
- unsigned char nKeySize;
414
- s >> nKeySize;
415
- if (nKeySize != 32 ) throw std::ios_base::failure (" Incorrect keysize in addrman deserialization" );
434
+ uint8_t compat;
435
+ s >> compat;
436
+ const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
437
+ if (lowest_compatible > FILE_FORMAT) {
438
+ throw std::ios_base::failure (strprintf (
439
+ " Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
440
+ " but the maximum supported by this version of %s is %u." ,
441
+ format, lowest_compatible, PACKAGE_NAME, static_cast <uint8_t >(FILE_FORMAT)));
442
+ }
443
+
416
444
s >> nKey;
417
445
s >> nNew;
418
446
s >> nTried;
0 commit comments