Skip to content

Commit

Permalink
merge bitcoin#19954: Complete the BIP155 implementation and upgrade t…
Browse files Browse the repository at this point in the history
…o TORv3
  • Loading branch information
kwvg committed May 25, 2021
1 parent 42872e5 commit 81741ad
Show file tree
Hide file tree
Showing 12 changed files with 315 additions and 31 deletions.
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
43 changes: 37 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,11 @@ 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));

// Signal ADDRv2 support (BIP155).
connman->PushMessage(pfrom, msg_maker.Make(NetMsgType::SENDADDRV2));

pfrom->nServices = nServices;
pfrom->SetAddrLocal(addrMe);
Expand Down Expand Up @@ -2409,17 +2414,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 +2474,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 +3983,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 +4003,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
29 changes: 26 additions & 3 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,26 @@ bool CNetAddr::IsInternal() const
return m_net == NET_INTERNAL;
}

bool CNetAddr::IsAddrV1Compatible() const
{
switch (m_net) {
case NET_IPV4:
case NET_IPV6:
case NET_INTERNAL:
return true;
case NET_ONION:
return m_addr.size() == ADDR_TORV2_SIZE;
case NET_I2P:
case NET_CJDNS:
return false;
case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE
case NET_MAX: // m_net is never and should not be set to NET_MAX
assert(false);
} // no default case, so the compiler can warn about missing cases

assert(false);
}

enum Network CNetAddr::GetNetwork() const
{
if (IsInternal())
Expand Down Expand Up @@ -737,9 +757,12 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co

std::vector<unsigned char> CNetAddr::GetAddrBytes() const
{
uint8_t serialized[V1_SERIALIZATION_SIZE];
SerializeV1Array(serialized);
return {std::begin(serialized), std::end(serialized)};
if (IsAddrV1Compatible()) {
uint8_t serialized[V1_SERIALIZATION_SIZE];
SerializeV1Array(serialized);
return {std::begin(serialized), std::end(serialized)};
}
return std::vector<unsigned char>(m_addr.begin(), m_addr.end());
}

uint64_t CNetAddr::GetHash() const
Expand Down
6 changes: 6 additions & 0 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ class CNetAddr
bool IsRoutable() const;
bool IsInternal() const;
bool IsValid() const;

/**
* Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
*/
bool IsAddrV1Compatible() const;

enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP(bool fUseGetnameinfo = true) const;
Expand Down
4 changes: 4 additions & 0 deletions src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace NetMsgType {
const char *VERSION="version";
const char *VERACK="verack";
const char *ADDR="addr";
const char *ADDRV2="addrv2";
const char *SENDADDRV2="sendaddrv2";
const char *INV="inv";
const char *GETDATA="getdata";
const char *MERKLEBLOCK="merkleblock";
Expand Down Expand Up @@ -86,6 +88,8 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::VERSION,
NetMsgType::VERACK,
NetMsgType::ADDR,
NetMsgType::ADDRV2,
NetMsgType::SENDADDRV2,
NetMsgType::INV,
NetMsgType::GETDATA,
NetMsgType::MERKLEBLOCK,
Expand Down
12 changes: 12 additions & 0 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ extern const char *VERACK;
* @see https://bitcoin.org/en/developer-reference#addr
*/
extern const char *ADDR;
/**
* The addrv2 message relays connection information for peers on the network just
* like the addr message, but is extended to allow gossiping of longer node
* addresses (see BIP155).
*/
extern const char *ADDRV2;
/**
* The sendaddrv2 message signals support for receiving ADDRV2 messages (BIP155).
* It also implies that its sender can encode as ADDRV2 and would send ADDRV2
* instead of ADDR to a peer that has signaled ADDRV2 support by sending SENDADDRV2.
*/
extern const char *SENDADDRV2;
/**
* The inv message (inventory message) transmits one or more inventories of
* objects known to the transmitting peer.
Expand Down
22 changes: 17 additions & 5 deletions src/serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
#include <prevector.h>
#include <span.h>

static const unsigned int MAX_SIZE = 0x02000000;
/**
* The maximum size of a serialized object in bytes or number of elements
* (for eg vectors) when the size is encoded as CompactSize.
*/
static constexpr uint64_t MAX_SIZE = 0x02000000;

/** Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
Expand Down Expand Up @@ -339,8 +343,14 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
return;
}

/**
* Decode a CompactSize-encoded variable-length integer.
*
* As these are primarily used to encode the size of vector-like serializations, by default a range
* check is performed. When used as a generic number encoding, range_check should be set to false.
*/
template<typename Stream>
uint64_t ReadCompactSize(Stream& is)
uint64_t ReadCompactSize(Stream& is, bool range_check = true)
{
uint8_t chSize = ser_readdata8(is);
uint64_t nSizeRet = 0;
Expand All @@ -366,8 +376,9 @@ uint64_t ReadCompactSize(Stream& is)
if (nSizeRet < 0x100000000ULL)
throw std::ios_base::failure("non-canonical ReadCompactSize()");
}
if (nSizeRet > (uint64_t)MAX_SIZE)
if (range_check && nSizeRet > MAX_SIZE) {
throw std::ios_base::failure("ReadCompactSize(): size too large");
}
return nSizeRet;
}

Expand Down Expand Up @@ -504,7 +515,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
#define FIXEDVARINTSBITSET(obj, size) CFixedVarIntsBitSet(REF(obj), (size))
#define AUTOBITSET(obj, size) CAutoBitSet(REF(obj), (size))
#define VARINT(obj, ...) Using<VarIntFormatter<__VA_ARGS__>>(obj)
#define COMPACTSIZE(obj) Using<CompactSizeFormatter>(obj)
#define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj)
#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj))

class CFixedBitSet
Expand Down Expand Up @@ -735,12 +746,13 @@ class BigEndian
};

/** Formatter for integers in CompactSize format. */
template<bool RangeCheck>
struct CompactSizeFormatter
{
template<typename Stream, typename I>
void Unser(Stream& s, I& v)
{
uint64_t n = ReadCompactSize<Stream>(s);
uint64_t n = ReadCompactSize<Stream>(s, RangeCheck);
if (n < std::numeric_limits<I>::min() || n > std::numeric_limits<I>::max()) {
throw std::ios_base::failure("CompactSize exceeds limit of type");
}
Expand Down
Loading

0 comments on commit 81741ad

Please sign in to comment.