net: CAddress & CAddrMan: (un)serialize as ADDRv2

Change the serialization of `CAddrMan` to serialize its addresses
in ADDRv2/BIP155 format by default. Introduce a new `CAddrMan` format
version (3).

Add support for ADDRv2 format in `CAddress` (un)serialization.

Co-authored-by: Carl Dong <contact@carldong.me>
This commit is contained in:
Vasil Dimov
2020-05-19 17:39:05 +02:00
parent 1d3ec2a1fd
commit 201a4596d9
5 changed files with 170 additions and 16 deletions

View File

@@ -12,6 +12,7 @@
#include <random.h>
#include <sync.h>
#include <timedata.h>
#include <tinyformat.h>
#include <util/system.h>
#include <fs.h>
@@ -264,6 +265,14 @@ protected:
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
//! Serialization versions.
enum class Format : uint8_t {
V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88
V1_DETERMINISTIC = 1, //!< for pre-asmap files
V2_ASMAP = 2, //!< for files including asmap version
V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format
};
// Compressed IP->ASN mapping, loaded from a file when a node starts.
// Should be always empty if no file was provided.
// This mapping is then used for bucketing nodes in Addrman.
@@ -285,8 +294,8 @@ public:
/**
* serialized format:
* * version byte (1 for pre-asmap files, 2 for files including asmap version)
* Serialized format.
* * version byte (@see `Format`)
* * 0x20 + nKey (serialized as if it were a vector, for backward compatibility)
* * nNew
* * nTried
@@ -313,13 +322,16 @@ public:
* We don't use SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*/
template<typename Stream>
void Serialize(Stream &s) const
template <typename Stream>
void Serialize(Stream& s_) const
{
LOCK(cs);
unsigned char nVersion = 2;
s << nVersion;
// Always serialize in the latest version (currently Format::V3_BIP155).
OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
s << static_cast<uint8_t>(Format::V3_BIP155);
s << ((unsigned char)32);
s << nKey;
s << nNew;
@@ -370,14 +382,34 @@ public:
s << asmap_version;
}
template<typename Stream>
void Unserialize(Stream& s)
template <typename Stream>
void Unserialize(Stream& s_)
{
LOCK(cs);
Clear();
unsigned char nVersion;
s >> nVersion;
Format format;
s_ >> Using<CustomUintFormatter<1>>(format);
static constexpr Format maximum_supported_format = Format::V3_BIP155;
if (format > maximum_supported_format) {
throw std::ios_base::failure(strprintf(
"Unsupported format of addrman database: %u. Maximum supported is %u. "
"Continuing operation without using the saved list of peers.",
static_cast<uint8_t>(format),
static_cast<uint8_t>(maximum_supported_format)));
}
int stream_version = s_.GetVersion();
if (format >= Format::V3_BIP155) {
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
// unserialize methods know that an address in addrv2 format is coming.
stream_version |= ADDRV2_FORMAT;
}
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version);
unsigned char nKeySize;
s >> nKeySize;
if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization");
@@ -386,7 +418,7 @@ public:
s >> nTried;
int nUBuckets = 0;
s >> nUBuckets;
if (nVersion != 0) {
if (format >= Format::V1_DETERMINISTIC) {
nUBuckets ^= (1 << 30);
}
@@ -449,7 +481,7 @@ public:
supplied_asmap_version = SerializeHash(m_asmap);
}
uint256 serialized_asmap_version;
if (nVersion > 1) {
if (format >= Format::V2_ASMAP) {
s >> serialized_asmap_version;
}
@@ -457,13 +489,13 @@ public:
CAddrInfo &info = mapInfo[n];
int bucket = entryToBucket[n];
int nUBucketPos = info.GetBucketPosition(nKey, true, bucket);
if (nVersion == 2 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 &&
if (format >= Format::V2_ASMAP && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 &&
info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) {
// Bucketing has not changed, using existing bucket positions for the new table
vvNew[bucket][nUBucketPos] = n;
info.nRefCount++;
} else {
// In case the new table data cannot be used (nVersion unknown, bucket count wrong or new asmap),
// In case the new table data cannot be used (format unknown, bucket count wrong or new asmap),
// try to give them a reference based on their primary source address.
LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n");
bucket = info.GetNewBucket(nKey, m_asmap);