Changeset View
Changeset View
Standalone View
Standalone View
src/addrman.h
// Copyright (c) 2012 Pieter Wuille | // Copyright (c) 2012 Pieter Wuille | ||||
// Copyright (c) 2012-2016 The Bitcoin Core developers | // Copyright (c) 2012-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#ifndef BITCOIN_ADDRMAN_H | #ifndef BITCOIN_ADDRMAN_H | ||||
#define BITCOIN_ADDRMAN_H | #define BITCOIN_ADDRMAN_H | ||||
#include <clientversion.h> | #include <clientversion.h> | ||||
#include <config/bitcoin-config.h> | |||||
#include <fs.h> | #include <fs.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#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> | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | |||||
class CAddrMan { | class CAddrMan { | ||||
friend class CAddrManTest; | friend class CAddrManTest; | ||||
protected: | protected: | ||||
//! critical section to protect the inner data structures | //! critical section to protect the inner data structures | ||||
mutable RecursiveMutex cs; | mutable RecursiveMutex cs; | ||||
private: | private: | ||||
//! Serialization versions. | |||||
enum 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, | |||||
}; | |||||
//! The maximum format this software knows it can unserialize. Also, we | |||||
//! always serialize in this format. The format (first byte in the | |||||
//! serialized stream) can be higher than this and still this software may | |||||
//! be able to unserialize the file - if the second byte (see | |||||
//! `lowest_compatible` in `Unserialize()`) is less or equal to this. | |||||
static constexpr Format FILE_FORMAT = Format::V3_BIP155; | |||||
//! The initial value of a field that is incremented every time an | |||||
//! incompatible format change is made (such that old software versions | |||||
//! would not be able to parse and understand the new file format). This is | |||||
//! 32 because we overtook the "key size" field which was 32 historically. | |||||
//! @note Don't increment this. Increment `lowest_compatible` in | |||||
//! `Serialize()` instead. | |||||
static constexpr uint8_t INCOMPATIBILITY_BASE = 32; | |||||
//! last used nId | //! last used nId | ||||
int nIdCount GUARDED_BY(cs); | int nIdCount GUARDED_BY(cs); | ||||
//! table with information about all nIds | //! table with information about all nIds | ||||
std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs); | std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs); | ||||
//! find an nId based on its network address | //! find an nId based on its network address | ||||
std::map<CNetAddr, int> mapAddr GUARDED_BY(cs); | std::map<CNetAddr, int> mapAddr GUARDED_BY(cs); | ||||
▲ Show 20 Lines • Show All 85 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 (@see `Format`) | * * format version byte (@see `Format`) | ||||
* * 0x20 + nKey (serialized as if it were a vector, for backward | * * lowest compatible format version byte. This is used to help old | ||||
* compatibility) | * software decide whether to parse the file. For example: | ||||
* * Bitcoin ABC version N knows how to parse up to format=3. If a new | |||||
* format=4 is introduced in version N+1 that is compatible with format=3 | |||||
* and it is known that version N will be able to parse it, then version N+1 | |||||
* will write (format=4, lowest_compatible=3) in the first two bytes of the | |||||
* file, and so version N will still try to parse it. | |||||
* * Bitcoin ABC version N+2 introduces a new incompatible format=5. It | |||||
* will write (format=5, lowest_compatible=5) and so any versions that do | |||||
* not know how to parse format=5 will not try to read the file. | |||||
* * nKey | |||||
* * 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: | ||||
* * number of elements | * * number of elements | ||||
* * for each element: index | * * for each element: index | ||||
Show All 13 Lines | public: | ||||
* 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); | ||||
// Always serialize in the latest version (currently Format::V3_BIP155). | // Always serialize in the latest version (FILE_FORMAT). | ||||
OverrideStream<Stream> s(&s_, s_.GetType(), | OverrideStream<Stream> s(&s_, s_.GetType(), | ||||
s_.GetVersion() | ADDRV2_FORMAT); | s_.GetVersion() | ADDRV2_FORMAT); | ||||
s << static_cast<uint8_t>(Format::V3_BIP155); | s << static_cast<uint8_t>(FILE_FORMAT); | ||||
s << uint8_t(32); | |||||
// Increment `lowest_compatible` iff a newly introduced format is | |||||
// incompatible with the previous one. | |||||
static constexpr uint8_t lowest_compatible = Format::V3_BIP155; | |||||
s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible); | |||||
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; | ||||
int nIds = 0; | int nIds = 0; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | public: | ||||
template <typename Stream> void Unserialize(Stream &s_) { | template <typename Stream> void Unserialize(Stream &s_) { | ||||
LOCK(cs); | LOCK(cs); | ||||
Clear(); | Clear(); | ||||
Format format; | Format format; | ||||
s_ >> Using<CustomUintFormatter<1>>(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(); | int stream_version = s_.GetVersion(); | ||||
if (format >= Format::V3_BIP155) { | if (format >= Format::V3_BIP155) { | ||||
// Add ADDRV2_FORMAT to the version so that the CNetAddr and | // Add ADDRV2_FORMAT to the version so that the CNetAddr and | ||||
// CAddress unserialize methods know that an address in addrv2 | // CAddress unserialize methods know that an address in addrv2 | ||||
// format is coming. | // format is coming. | ||||
stream_version |= ADDRV2_FORMAT; | stream_version |= ADDRV2_FORMAT; | ||||
} | } | ||||
OverrideStream<Stream> s(&s_, s_.GetType(), stream_version); | OverrideStream<Stream> s(&s_, s_.GetType(), stream_version); | ||||
uint8_t nKeySize; | uint8_t compat; | ||||
s >> nKeySize; | s >> compat; | ||||
if (nKeySize != 32) { | const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE; | ||||
throw std::ios_base::failure( | if (lowest_compatible > FILE_FORMAT) { | ||||
"Incorrect keysize in addrman deserialization"); | throw std::ios_base::failure(strprintf( | ||||
"Unsupported format of addrman database: %u. It is compatible " | |||||
"with formats >=%u, " | |||||
"but the maximum supported by this version of %s is %u.", | |||||
format, lowest_compatible, PACKAGE_NAME, | |||||
static_cast<uint8_t>(FILE_FORMAT))); | |||||
} | } | ||||
s >> nKey; | s >> nKey; | ||||
s >> nNew; | s >> nNew; | ||||
s >> nTried; | s >> nTried; | ||||
int nUBuckets = 0; | int nUBuckets = 0; | ||||
s >> nUBuckets; | s >> nUBuckets; | ||||
if (format >= Format::V1_DETERMINISTIC) { | if (format >= Format::V1_DETERMINISTIC) { | ||||
▲ Show 20 Lines • Show All 285 Lines • Show Last 20 Lines |