Changeset View
Changeset View
Standalone View
Standalone View
src/addrman.h
Show All 11 Lines | |||||
#include <netaddress.h> | #include <netaddress.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <random.h> | #include <random.h> | ||||
#include <streams.h> | #include <streams.h> | ||||
#include <sync.h> | #include <sync.h> | ||||
#include <timedata.h> | #include <timedata.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <tinyformat.h> | |||||
#include <cstdint> | #include <cstdint> | ||||
#include <iostream> | #include <iostream> | ||||
#include <map> | #include <map> | ||||
#include <set> | #include <set> | ||||
#include <vector> | #include <vector> | ||||
/** | /** | ||||
* Extended statistics about a CAddress | * Extended statistics about a CAddress | ||||
▲ Show 20 Lines • Show All 266 Lines • ▼ Show 20 Lines | #endif | ||||
void Connected_(const CService &addr, int64_t nTime) | void Connected_(const CService &addr, int64_t nTime) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs); | EXCLUSIVE_LOCKS_REQUIRED(cs); | ||||
//! Update an entry's service bits. | //! Update an entry's service bits. | ||||
void SetServices_(const CService &addr, ServiceFlags nServices) | void SetServices_(const CService &addr, ServiceFlags nServices) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs); | EXCLUSIVE_LOCKS_REQUIRED(cs); | ||||
public: | public: | ||||
//! Serialization versions. | |||||
enum class Format : uint8_t { | |||||
//! historic format, before commit e6b343d88 | |||||
V0_HISTORICAL = 0, | |||||
//! for pre-asmap files | |||||
V1_DETERMINISTIC = 1, | |||||
//! for files including asmap version | |||||
V2_ASMAP = 2, | |||||
//! same as V2_ASMAP plus addresses are in BIP155 format | |||||
V3_BIP155 = 3, | |||||
}; | |||||
// Compressed IP->ASN mapping, loaded from a file when a node starts. | // Compressed IP->ASN mapping, loaded from a file when a node starts. | ||||
// Should be always empty if no file was provided. | // Should be always empty if no file was provided. | ||||
// This mapping is then used for bucketing nodes in Addrman. | // This mapping is then used for bucketing nodes in Addrman. | ||||
// | // | ||||
// If asmap is provided, nodes will be bucketed by | // If asmap is provided, nodes will be bucketed by | ||||
// AS they belong to, in order to make impossible for a node | // AS they belong to, in order to make impossible for a node | ||||
// to connect to several nodes hosted in a single AS. | // to connect to several nodes hosted in a single AS. | ||||
// This is done in response to Erebus attack, but also to generally | // This is done in response to Erebus attack, but also to generally | ||||
// diversify the connections every node creates, | // diversify the connections every node creates, | ||||
// especially useful when a large fraction of nodes | // especially useful when a large fraction of nodes | ||||
// operate under a couple of cloud providers. | // operate under a couple of cloud providers. | ||||
// | // | ||||
// If a new asmap was provided, the existing records | // If a new asmap was provided, the existing records | ||||
// would be re-bucketed accordingly. | // would be re-bucketed accordingly. | ||||
std::vector<bool> m_asmap; | std::vector<bool> m_asmap; | ||||
// Read asmap from provided binary file | // Read asmap from provided binary file | ||||
static std::vector<bool> DecodeAsmap(fs::path path); | static std::vector<bool> DecodeAsmap(fs::path path); | ||||
/** | /** | ||||
* serialized format: | * Serialized format. | ||||
* * version byte (1 for pre-asmap files, 2 for files including asmap | * * version byte (@see `Format`) | ||||
* version) | |||||
* * 0x20 + nKey (serialized as if it were a vector, for backward | * * 0x20 + nKey (serialized as if it were a vector, for backward | ||||
* compatibility) | * compatibility) | ||||
* * nNew | * * nNew | ||||
* * nTried | * * nTried | ||||
* * number of "new" buckets XOR 2**30 | * * number of "new" buckets XOR 2**30 | ||||
* * all nNew addrinfos in vvNew | * * all nNew addrinfos in vvNew | ||||
* * all nTried addrinfos in vvTried | * * all nTried addrinfos in vvTried | ||||
* * for each bucket: | * * for each bucket: | ||||
Show All 12 Lines | public: | ||||
* | * | ||||
* This format is more complex, but significantly smaller (at most 1.5 MiB), | * This format is more complex, but significantly smaller (at most 1.5 MiB), | ||||
* and supports changes to the ADDRMAN_ parameters without breaking the | * and supports changes to the ADDRMAN_ parameters without breaking the | ||||
* on-disk structure. | * on-disk structure. | ||||
* | * | ||||
* We don't use SERIALIZE_METHODS since the serialization and | * We don't use SERIALIZE_METHODS since the serialization and | ||||
* deserialization code has very little in common. | * 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); | LOCK(cs); | ||||
uint8_t nVersion = 2; | // Always serialize in the latest version (currently Format::V3_BIP155). | ||||
s << nVersion; | |||||
OverrideStream<Stream> s(&s_, s_.GetType(), | |||||
s_.GetVersion() | ADDRV2_FORMAT); | |||||
s << static_cast<uint8_t>(Format::V3_BIP155); | |||||
s << uint8_t(32); | s << uint8_t(32); | ||||
s << nKey; | s << nKey; | ||||
s << nNew; | s << nNew; | ||||
s << nTried; | s << nTried; | ||||
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); | int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); | ||||
s << nUBuckets; | s << nUBuckets; | ||||
std::map<int, int> mapUnkIds; | std::map<int, int> mapUnkIds; | ||||
Show All 35 Lines | template <typename Stream> void Serialize(Stream &s_) const { | ||||
// can be ignored by older clients for backward compatibility. | // can be ignored by older clients for backward compatibility. | ||||
uint256 asmap_version; | uint256 asmap_version; | ||||
if (m_asmap.size() != 0) { | if (m_asmap.size() != 0) { | ||||
asmap_version = SerializeHash(m_asmap); | asmap_version = SerializeHash(m_asmap); | ||||
} | } | ||||
s << asmap_version; | s << asmap_version; | ||||
} | } | ||||
template <typename Stream> void Unserialize(Stream &s) { | template <typename Stream> void Unserialize(Stream &s_) { | ||||
LOCK(cs); | LOCK(cs); | ||||
Clear(); | Clear(); | ||||
uint8_t 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); | |||||
uint8_t nKeySize; | uint8_t nKeySize; | ||||
s >> nKeySize; | s >> nKeySize; | ||||
if (nKeySize != 32) { | if (nKeySize != 32) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"Incorrect keysize in addrman deserialization"); | "Incorrect keysize in addrman deserialization"); | ||||
} | } | ||||
s >> nKey; | s >> nKey; | ||||
s >> nNew; | s >> nNew; | ||||
s >> nTried; | s >> nTried; | ||||
int nUBuckets = 0; | int nUBuckets = 0; | ||||
s >> nUBuckets; | s >> nUBuckets; | ||||
if (nVersion != 0) { | if (format >= Format::V1_DETERMINISTIC) { | ||||
nUBuckets ^= (1 << 30); | nUBuckets ^= (1 << 30); | ||||
} | } | ||||
if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { | if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { | ||||
throw std::ios_base::failure( | throw std::ios_base::failure( | ||||
"Corrupt CAddrMan serialization, nNew exceeds limit."); | "Corrupt CAddrMan serialization, nNew exceeds limit."); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | template <typename Stream> void Unserialize(Stream &s_) { | ||||
} | } | ||||
} | } | ||||
uint256 supplied_asmap_version; | uint256 supplied_asmap_version; | ||||
if (m_asmap.size() != 0) { | if (m_asmap.size() != 0) { | ||||
supplied_asmap_version = SerializeHash(m_asmap); | supplied_asmap_version = SerializeHash(m_asmap); | ||||
} | } | ||||
uint256 serialized_asmap_version; | uint256 serialized_asmap_version; | ||||
if (nVersion > 1) { | if (format >= Format::V2_ASMAP) { | ||||
s >> serialized_asmap_version; | s >> serialized_asmap_version; | ||||
} | } | ||||
for (int n = 0; n < nNew; n++) { | for (int n = 0; n < nNew; n++) { | ||||
CAddrInfo &info = mapInfo[n]; | CAddrInfo &info = mapInfo[n]; | ||||
int bucket = entryToBucket[n]; | int bucket = entryToBucket[n]; | ||||
int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); | int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); | ||||
if (nVersion == 2 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && | if (format >= Format::V2_ASMAP && | ||||
nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && | |||||
vvNew[bucket][nUBucketPos] == -1 && | vvNew[bucket][nUBucketPos] == -1 && | ||||
info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && | info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && | ||||
serialized_asmap_version == supplied_asmap_version) { | serialized_asmap_version == supplied_asmap_version) { | ||||
// Bucketing has not changed, using existing bucket positions | // Bucketing has not changed, using existing bucket positions | ||||
// for the new table | // for the new table | ||||
vvNew[bucket][nUBucketPos] = n; | vvNew[bucket][nUBucketPos] = n; | ||||
info.nRefCount++; | info.nRefCount++; | ||||
} else { | } else { | ||||
// In case the new table data cannot be used (nVersion unknown, | // In case the new table data cannot be used (format unknown, | ||||
// bucket count wrong or new asmap), try to give them a | // bucket count wrong or new asmap), try to give them a | ||||
// reference based on their primary source address. | // reference based on their primary source address. | ||||
LogPrint(BCLog::ADDRMAN, | LogPrint(BCLog::ADDRMAN, | ||||
"Bucketing method was updated, re-bucketing addrman " | "Bucketing method was updated, re-bucketing addrman " | ||||
"entries from disk\n"); | "entries from disk\n"); | ||||
bucket = info.GetNewBucket(nKey, m_asmap); | bucket = info.GetNewBucket(nKey, m_asmap); | ||||
nUBucketPos = info.GetBucketPosition(nKey, true, bucket); | nUBucketPos = info.GetBucketPosition(nKey, true, bucket); | ||||
if (vvNew[bucket][nUBucketPos] == -1) { | if (vvNew[bucket][nUBucketPos] == -1) { | ||||
▲ Show 20 Lines • Show All 192 Lines • Show Last 20 Lines |