77#define BITCOIN_ADDRMAN_H
88
99#include < clientversion.h>
10+ #include < config/bitcoin-config.h>
1011#include < netaddress.h>
1112#include < protocol.h>
1213#include < random.h>
@@ -176,6 +177,28 @@ friend class CAddrManTest;
176177 mutable RecursiveMutex cs;
177178
178179private:
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+
179202 // ! last used nId
180203 int nIdCount GUARDED_BY (cs);
181204
@@ -265,14 +288,6 @@ friend class CAddrManTest;
265288 void SetServices_ (const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
266289
267290public:
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-
276291 // Compressed IP->ASN mapping, loaded from a file when a node starts.
277292 // Should be always empty if no file was provided.
278293 // This mapping is then used for bucketing nodes in Addrman.
@@ -295,8 +310,18 @@ friend class CAddrManTest;
295310
296311 /* *
297312 * 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
300325 * * nNew
301326 * * nTried
302327 * * number of "new" buckets XOR 2**30
@@ -327,12 +352,17 @@ friend class CAddrManTest;
327352 {
328353 LOCK (cs);
329354
330- // Always serialize in the latest version (currently Format::V3_BIP155 ).
355+ // Always serialize in the latest version (FILE_FORMAT ).
331356
332357 OverrideStream<Stream> s (&s_, s_.GetType (), s_.GetVersion () | ADDRV2_FORMAT);
333358
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+
336366 s << nKey;
337367 s << nNew;
338368 s << nTried;
@@ -392,15 +422,6 @@ friend class CAddrManTest;
392422 Format format;
393423 s_ >> Using<CustomUintFormatter<1 >>(format);
394424
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-
404425 int stream_version = s_.GetVersion ();
405426 if (format >= Format::V3_BIP155) {
406427 // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
@@ -410,9 +431,16 @@ friend class CAddrManTest;
410431
411432 OverrideStream<Stream> s (&s_, s_.GetType (), stream_version);
412433
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+
416444 s >> nKey;
417445 s >> nNew;
418446 s >> nTried;
0 commit comments