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 Core 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 Core version N+2 introduces a new incompatible format=5. It | |||||||||||||||
majcostaUnsubmitted Not Done Inline Actions
majcosta: | |||||||||||||||
* 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 |