mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 06:43:45 +01:00
net: advertise support for ADDRv2 via new message
Introduce a new message `sendaddrv2` to signal support for ADDRv2. Send the new message immediately after sending the `VERACK` message. Add support for receiving and parsing ADDRv2 messages. Send ADDRv2 messages (instead of ADDR) to a peer if he has advertised support for it. Co-authored-by: Carl Dong <contact@carldong.me>
This commit is contained in:
12
src/net.h
12
src/net.h
@@ -868,6 +868,11 @@ public:
|
||||
bool m_legacyWhitelisted{false};
|
||||
bool fClient{false}; // set by version message
|
||||
bool m_limited_node{false}; //after BIP159, set by version message
|
||||
/**
|
||||
* 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{false};
|
||||
// Setting fDisconnect to true will cause the node to be disconnected the
|
||||
// next time DisconnectNodes() runs
|
||||
@@ -1115,11 +1120,16 @@ public:
|
||||
|
||||
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.
|
||||
assert(m_addr_known);
|
||||
if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey())) {
|
||||
if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey()) && addr_format_supported) {
|
||||
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
|
||||
vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
|
||||
} else {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <random.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <scheduler.h>
|
||||
#include <streams.h>
|
||||
#include <tinyformat.h>
|
||||
#include <txmempool.h>
|
||||
#include <util/check.h> // For NDEBUG compile time check
|
||||
@@ -2408,11 +2409,16 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
||||
pfrom.SetCommonVersion(greatest_common_version);
|
||||
pfrom.nVersion = nVersion;
|
||||
|
||||
const CNetMsgMaker msg_maker(greatest_common_version);
|
||||
|
||||
if (greatest_common_version >= WTXID_RELAY_VERSION) {
|
||||
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::WTXIDRELAY));
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::WTXIDRELAY));
|
||||
}
|
||||
|
||||
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::VERACK));
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
|
||||
|
||||
// Signal ADDRv2 support (BIP155).
|
||||
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDADDRV2));
|
||||
|
||||
pfrom.nServices = nServices;
|
||||
pfrom.SetAddrLocal(addrMe);
|
||||
@@ -2582,16 +2588,25 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_type == NetMsgType::ADDR) {
|
||||
if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRV2) {
|
||||
int stream_version = vRecv.GetVersion();
|
||||
if (msg_type == 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;
|
||||
|
||||
if (!pfrom.RelayAddrsWithConn()) {
|
||||
return;
|
||||
}
|
||||
if (vAddr.size() > MAX_ADDR_TO_SEND)
|
||||
{
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("addr message size = %u", vAddr.size()));
|
||||
Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2635,6 +2650,11 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_type == NetMsgType::SENDADDRV2) {
|
||||
pfrom.m_wants_addrv2 = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_type == NetMsgType::SENDHEADERS) {
|
||||
LOCK(cs_main);
|
||||
State(pfrom.GetId())->fPreferHeaders = true;
|
||||
@@ -4095,6 +4115,17 @@ bool PeerManager::SendMessages(CNode* pto)
|
||||
std::vector<CAddress> vAddr;
|
||||
vAddr.reserve(pto->vAddrToSend.size());
|
||||
assert(pto->m_addr_known);
|
||||
|
||||
const char* msg_type;
|
||||
int make_flags;
|
||||
if (pto->m_wants_addrv2) {
|
||||
msg_type = NetMsgType::ADDRV2;
|
||||
make_flags = ADDRV2_FORMAT;
|
||||
} else {
|
||||
msg_type = NetMsgType::ADDR;
|
||||
make_flags = 0;
|
||||
}
|
||||
|
||||
for (const CAddress& addr : pto->vAddrToSend)
|
||||
{
|
||||
if (!pto->m_addr_known->contains(addr.GetKey()))
|
||||
@@ -4104,14 +4135,14 @@ bool PeerManager::SendMessages(CNode* pto)
|
||||
// receiver rejects addr messages larger than MAX_ADDR_TO_SEND
|
||||
if (vAddr.size() >= MAX_ADDR_TO_SEND)
|
||||
{
|
||||
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
|
||||
m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr));
|
||||
vAddr.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
pto->vAddrToSend.clear();
|
||||
if (!vAddr.empty())
|
||||
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
|
||||
m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr));
|
||||
// we only send the big addr message once
|
||||
if (pto->vAddrToSend.capacity() > 40)
|
||||
pto->vAddrToSend.shrink_to_fit();
|
||||
|
||||
@@ -474,6 +474,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())
|
||||
@@ -744,9 +764,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
|
||||
|
||||
@@ -173,6 +173,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() const;
|
||||
|
||||
@@ -14,6 +14,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";
|
||||
@@ -52,6 +54,8 @@ const static std::string allNetMessageTypes[] = {
|
||||
NetMsgType::VERSION,
|
||||
NetMsgType::VERACK,
|
||||
NetMsgType::ADDR,
|
||||
NetMsgType::ADDRV2,
|
||||
NetMsgType::SENDADDRV2,
|
||||
NetMsgType::INV,
|
||||
NetMsgType::GETDATA,
|
||||
NetMsgType::MERKLEBLOCK,
|
||||
|
||||
@@ -76,6 +76,18 @@ extern const char* VERACK;
|
||||
* network.
|
||||
*/
|
||||
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.
|
||||
|
||||
@@ -212,6 +212,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsIPv4());
|
||||
|
||||
BOOST_CHECK(addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
|
||||
|
||||
// IPv4, INADDR_NONE
|
||||
@@ -220,6 +221,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsIPv4());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
|
||||
|
||||
// IPv4, casual
|
||||
@@ -228,6 +230,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsIPv4());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
|
||||
|
||||
// IPv6, in6addr_any
|
||||
@@ -236,6 +239,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsIPv6());
|
||||
|
||||
BOOST_CHECK(addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "::");
|
||||
|
||||
// IPv6, casual
|
||||
@@ -244,6 +248,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsIPv6());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
|
||||
|
||||
// TORv2
|
||||
@@ -252,6 +257,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsTor());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
|
||||
|
||||
// TORv3
|
||||
@@ -261,6 +267,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsTor());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), torv3_addr);
|
||||
|
||||
// TORv3, broken, with wrong checksum
|
||||
@@ -285,6 +292,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
|
||||
BOOST_REQUIRE(addr.IsInternal());
|
||||
|
||||
BOOST_CHECK(!addr.IsBindAny());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
|
||||
|
||||
// Totally bogus
|
||||
@@ -379,6 +387,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsIPv4());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "1.2.3.4");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
|
||||
@@ -415,6 +424,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsIPv6());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "102:304:506:708:90a:b0c:d0e:f10");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
|
||||
@@ -426,6 +436,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
// sha256(name)[0:10]
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsInternal());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "zklycewkdo64v6wc.internal");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
|
||||
@@ -461,6 +472,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsTor());
|
||||
BOOST_CHECK(addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
|
||||
@@ -482,6 +494,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsTor());
|
||||
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(),
|
||||
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
@@ -503,6 +516,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
"f98232ae42d4b6fd2fa81952dfe36a87"));
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsI2P());
|
||||
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(),
|
||||
"ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
@@ -524,6 +539,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
|
||||
));
|
||||
s >> addr;
|
||||
BOOST_CHECK(addr.IsValid());
|
||||
BOOST_CHECK(addr.IsCJDNS());
|
||||
BOOST_CHECK(!addr.IsAddrV1Compatible());
|
||||
BOOST_CHECK_EQUAL(addr.ToString(), "fc00:1:2:3:4:5:6:7");
|
||||
BOOST_REQUIRE(s.empty());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user