Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
* wallets/db.log: wallet database log file; since 0.16.0
* wallets/wallet.dat: personal wallet (BDB) with keys and transactions; since 0.16.0
* .cookie: session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown)
* onion_private_key: cached Tor hidden service private key for `-listenonion`
* onion_v3_private_key: cached Tor hidden service private key for `-listenonion`
* guisettings.ini.bak: backup of former GUI settings after `-resetguisettings` is used
60 changes: 46 additions & 14 deletions src/addrman.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <random.h>
#include <sync.h>
#include <timedata.h>
#include <tinyformat.h>
#include <util.h>

#include <fs.h>
Expand Down Expand Up @@ -293,6 +294,14 @@ class CAddrMan
CAddrInfo GetAddressInfo_(const CService& addr);

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.
Expand All @@ -314,8 +323,8 @@ class CAddrMan


/**
* 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
Expand All @@ -342,13 +351,16 @@ class CAddrMan
* 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;
Expand Down Expand Up @@ -399,14 +411,34 @@ class CAddrMan
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");
Expand All @@ -415,7 +447,7 @@ class CAddrMan
s >> nTried;
int nUBuckets = 0;
s >> nUBuckets;
if (nVersion != 0) {
if (format >= Format::V1_DETERMINISTIC) {
nUBuckets ^= (1 << 30);
}

Expand Down Expand Up @@ -478,21 +510,21 @@ class CAddrMan
supplied_asmap_version = SerializeHash(m_asmap);
}
uint256 serialized_asmap_version;
if (nVersion > 1) {
if (format >= Format::V2_ASMAP) {
s >> serialized_asmap_version;
}

for (int n = 0; n < nNew; n++) {
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);
Expand Down
7 changes: 7 additions & 0 deletions src/crypto/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ void static inline WriteLE64(unsigned char* ptr, uint64_t x)
memcpy(ptr, (char*)&v, 8);
}

uint16_t static inline ReadBE16(const unsigned char* ptr)
{
uint16_t x;
memcpy((char*)&x, ptr, 2);
return be16toh(x);
}

uint32_t static inline ReadBE32(const unsigned char* ptr)
{
uint32_t x;
Expand Down
13 changes: 12 additions & 1 deletion src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,12 @@ class CNode
bool fClient;
bool m_limited_node; //after BIP159
const bool fInbound;

/**
* Whether the peer has signaled support for receiving ADDRv2 (BIP155)
* messages, implying a preference to receive ADDRv2 instead of ADDR ones.
*/
std::atomic_bool m_wants_addrv2{false};
std::atomic_bool fSuccessfullyConnected;
std::atomic_bool fDisconnect;
std::atomic<int64_t> nDisconnectLingerTime{0};
Expand Down Expand Up @@ -1063,10 +1069,15 @@ class CNode

void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
{
// Whether the peer supports the address in `_addr`. For example,
// nodes that do not implement BIP155 cannot receive Tor v3 addresses
// because they require ADDRv2 (BIP155) encoding.
const bool addr_format_supported = m_wants_addrv2 || _addr.IsAddrV1Compatible();

// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey()) && addr_format_supported) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
} else {
Expand Down
44 changes: 38 additions & 6 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <random.h>
#include <reverse_iterator.h>
#include <scheduler.h>
#include <streams.h>
#include <tinyformat.h>
#include <txdb.h>
#include <txmempool.h>
Expand Down Expand Up @@ -2248,7 +2249,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
}

connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
const CNetMsgMaker msg_maker(INIT_PROTO_VERSION);
connman->PushMessage(pfrom, msg_maker.Make(NetMsgType::VERACK));

pfrom->nServices = nServices;
pfrom->SetAddrLocal(addrMe);
Expand Down Expand Up @@ -2355,6 +2357,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
CMNAuth::PushMNAUTH(pfrom, *connman);
}

// Signal ADDRv2 support (BIP155).
// NOTE: Should NOT send this prior to MNMAUTH.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDADDRV2));

// Tell our peer we prefer to receive headers rather than inv's
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
Expand Down Expand Up @@ -2409,17 +2415,27 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
}

if (strCommand == NetMsgType::ADDR) {
if (strCommand == NetMsgType::ADDR || strCommand == NetMsgType::ADDRV2) {
int stream_version = vRecv.GetVersion();
if (strCommand == NetMsgType::ADDRV2) {
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
// unserialize methods know that an address in v2 format is coming.
stream_version |= ADDRV2_FORMAT;
}

OverrideStream<CDataStream> s(&vRecv, vRecv.GetType(), stream_version);
std::vector<CAddress> vAddr;
vRecv >> vAddr;

s >> vAddr;

// Don't want addr from older versions unless seeding
if (pfrom->nVersion < CADDR_TIME_VERSION && connman->GetAddressCount() > 1000)
return true;

if (vAddr.size() > 1000)
{
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 20, strprintf("message addr size() = %u", vAddr.size()));
Misbehaving(pfrom->GetId(), 20, strprintf("%s message size = %u", strCommand, vAddr.size()));
return false;
}

Expand Down Expand Up @@ -2459,6 +2475,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}

if (strCommand == NetMsgType::SENDADDRV2) {
pfrom->m_wants_addrv2 = true;
return true;
}

if (strCommand == NetMsgType::SENDHEADERS) {
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
Expand Down Expand Up @@ -3963,6 +3984,17 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
std::vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());

const char* strCommand;
int make_flags;
if (pto->m_wants_addrv2) {
strCommand = NetMsgType::ADDRV2;
make_flags = ADDRV2_FORMAT;
} else {
strCommand = NetMsgType::ADDR;
make_flags = 0;
}

for (const CAddress& addr : pto->vAddrToSend)
{
if (!pto->addrKnown.contains(addr.GetKey()))
Expand All @@ -3972,14 +4004,14 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
connman->PushMessage(pto, msgMaker.Make(make_flags, strCommand, vAddr));
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
connman->PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
connman->PushMessage(pto, msgMaker.Make(make_flags, strCommand, vAddr));
// we only send the big addr message once
if (pto->vAddrToSend.capacity() > 40)
pto->vAddrToSend.shrink_to_fit();
Expand Down
Loading