77#ifndef BITCOIN_ADDRMAN_H
88#define BITCOIN_ADDRMAN_H
99
10+ #if defined(HAVE_CONFIG_H)
11+ #include " config/pivx-config.h"
12+ #endif // HAVE_CONFIG_H
13+
1014#include " clientversion.h"
1115#include " netaddress.h"
1216#include " protocol.h"
@@ -183,6 +187,28 @@ friend class CAddrManTest;
183187 mutable RecursiveMutex cs;
184188
185189private:
190+ // ! Serialization versions.
191+ enum Format : uint8_t {
192+ V0_HISTORICAL = 0 , // !< historic format, before commit e6b343d88
193+ V1_DETERMINISTIC = 1 , // !< for pre-asmap files
194+ V2_ASMAP = 2 , // !< for files including asmap version
195+ V3_BIP155 = 3 , // !< same as V2_ASMAP plus addresses are in BIP155 format
196+ };
197+
198+ // ! The maximum format this software knows it can unserialize. Also, we always serialize
199+ // ! in this format.
200+ // ! The format (first byte in the serialized stream) can be higher than this and
201+ // ! still this software may be able to unserialize the file - if the second byte
202+ // ! (see `lowest_compatible` in `Unserialize()`) is less or equal to this.
203+ static constexpr Format FILE_FORMAT = Format::V3_BIP155;
204+
205+ // ! The initial value of a field that is incremented every time an incompatible format
206+ // ! change is made (such that old software versions would not be able to parse and
207+ // ! understand the new file format). This is 32 because we overtook the "key size"
208+ // ! field which was 32 historically.
209+ // ! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead.
210+ static constexpr uint8_t INCOMPATIBILITY_BASE = 32 ;
211+
186212 // ! last used nId
187213 int nIdCount GUARDED_BY (cs);
188214
@@ -272,14 +298,6 @@ friend class CAddrManTest;
272298 void SetServices_ (const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
273299
274300public:
275- // ! Serialization versions.
276- enum class Format : uint8_t {
277- V0_HISTORICAL = 0 , // !< historic format, before commit e6b343d88
278- V1_DETERMINISTIC = 1 , // !< for pre-asmap files
279- V2_ASMAP = 2 , // !< for files including asmap version
280- V3_BIP155 = 3 , // !< same as V2_ASMAP plus addresses are in BIP155 format
281- };
282-
283301 // Compressed IP->ASN mapping, loaded from a file when a node starts.
284302 // Should be always empty if no file was provided.
285303 // This mapping is then used for bucketing nodes in Addrman.
@@ -302,8 +320,18 @@ friend class CAddrManTest;
302320
303321 /* *
304322 * Serialized format.
305- * * version byte (@see `Format`)
306- * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
323+ * * format version byte (@see `Format`)
324+ * * lowest compatible format version byte. This is used to help old software decide
325+ * whether to parse the file. For example:
326+ * * PIVX Core version N knows how to parse up to format=3. If a new format=4 is
327+ * introduced in version N+1 that is compatible with format=3 and it is known that
328+ * version N will be able to parse it, then version N+1 will write
329+ * (format=4, lowest_compatible=3) in the first two bytes of the file, and so
330+ * version N will still try to parse it.
331+ * * PIVX Core version N+2 introduces a new incompatible format=5. It will write
332+ * (format=5, lowest_compatible=5) and so any versions that do not know how to parse
333+ * format=5 will not try to read the file.
334+ * * nKey
307335 * * nNew
308336 * * nTried
309337 * * number of "new" buckets XOR 2**30
@@ -334,12 +362,17 @@ friend class CAddrManTest;
334362 {
335363 LOCK (cs);
336364
337- // Always serialize in the latest version (currently Format::V3_BIP155 ).
365+ // Always serialize in the latest version (FILE_FORMAT ).
338366
339367 OverrideStream<Stream> s (&s_, s_.GetType (), s_.GetVersion () | ADDRV2_FORMAT);
340368
341- s << static_cast <uint8_t >(Format::V3_BIP155);
342- s << ((unsigned char )32 );
369+ s << static_cast <uint8_t >(FILE_FORMAT);
370+
371+ // Increment `lowest_compatible` if a newly introduced format is incompatible with
372+ // the previous one.
373+ static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
374+ s << static_cast <uint8_t >(INCOMPATIBILITY_BASE + lowest_compatible);
375+
343376 s << nKey;
344377 s << nNew;
345378 s << nTried;
@@ -399,15 +432,6 @@ friend class CAddrManTest;
399432 Format format;
400433 s_ >> Using<CustomUintFormatter<1 >>(format);
401434
402- static constexpr Format maximum_supported_format = Format::V3_BIP155;
403- if (format > maximum_supported_format) {
404- throw std::ios_base::failure (strprintf (
405- " Unsupported format of addrman database: %u. Maximum supported is %u. "
406- " Continuing operation without using the saved list of peers." ,
407- static_cast <uint8_t >(format),
408- static_cast <uint8_t >(maximum_supported_format)));
409- }
410-
411435 int stream_version = s_.GetVersion ();
412436 if (format >= Format::V3_BIP155) {
413437 // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
@@ -417,9 +441,16 @@ friend class CAddrManTest;
417441
418442 OverrideStream<Stream> s (&s_, s_.GetType (), stream_version);
419443
420- unsigned char nKeySize;
421- s >> nKeySize;
422- if (nKeySize != 32 ) throw std::ios_base::failure (" Incorrect keysize in addrman deserialization" );
444+ uint8_t compat;
445+ s >> compat;
446+ const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
447+ if (lowest_compatible > FILE_FORMAT) {
448+ throw std::ios_base::failure (strprintf (
449+ " Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
450+ " but the maximum supported by this version of %s is %u." ,
451+ format, lowest_compatible, PACKAGE_NAME, static_cast <uint8_t >(FILE_FORMAT)));
452+ }
453+
423454 s >> nKey;
424455 s >> nNew;
425456 s >> nTried;
0 commit comments