Skip to content

Commit 1d21406

Browse files
vasilddongcarl
andcommitted
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 <[email protected]>
1 parent 896a5af commit 1d21406

File tree

11 files changed

+227
-22
lines changed

11 files changed

+227
-22
lines changed

src/net.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,11 @@ class CNode
852852
bool m_legacyWhitelisted{false};
853853
bool fClient{false}; // set by version message
854854
bool m_limited_node{false}; //after BIP159, set by version message
855+
/**
856+
* Whether the peer has signaled support for receiving ADDRv2 (BIP155)
857+
* messages, implying a preference to receive ADDRv2 instead of ADDR ones.
858+
*/
859+
std::atomic_bool m_wants_addrv2{false};
855860
std::atomic_bool fSuccessfullyConnected{false};
856861
// Setting fDisconnect to true will cause the node to be disconnected the
857862
// next time DisconnectNodes() runs
@@ -1101,11 +1106,16 @@ class CNode
11011106

11021107
void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
11031108
{
1109+
// Whether the peer supports the address in `_addr`. For example,
1110+
// nodes that do not implement BIP155 cannot receive Tor v3 addresses
1111+
// because they require ADDRv2 (BIP155) encoding.
1112+
const bool addr_format_supported = m_wants_addrv2 || _addr.IsAddrV1Compatible();
1113+
11041114
// Known checking here is only to save space from duplicates.
11051115
// SendMessages will filter it again for knowns that were added
11061116
// after addresses were pushed.
11071117
assert(m_addr_known);
1108-
if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey())) {
1118+
if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey()) && addr_format_supported) {
11091119
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
11101120
vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr;
11111121
} else {

src/net_processing.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,9 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
24102410

24112411
m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERACK));
24122412

2413+
// Signal ADDRv2 support (BIP155).
2414+
m_connman.PushMessage(&pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::SENDADDRv2));
2415+
24132416
pfrom.nServices = nServices;
24142417
pfrom.SetAddrLocal(addrMe);
24152418
{
@@ -2584,9 +2587,29 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
25842587
return;
25852588
}
25862589

2587-
if (msg_type == NetMsgType::ADDR) {
2590+
if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRv2) {
2591+
const auto version_orig = vRecv.GetVersion();
2592+
if (msg_type == NetMsgType::ADDRv2) {
2593+
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
2594+
// unserialize methods know that an address in v2 format is coming.
2595+
vRecv.SetVersion(version_orig | ADDRV2_FORMAT);
2596+
}
25882597
std::vector<CAddress> vAddr;
2589-
vRecv >> vAddr;
2598+
2599+
try {
2600+
vRecv >> vAddr;
2601+
} catch (const std::exception& e) {
2602+
vRecv.SetVersion(version_orig);
2603+
2604+
LOCK(cs_main);
2605+
Misbehaving(pfrom.GetId(), 20,
2606+
strprintf(
2607+
"Supplied us with a message that contains an unparsable address: %s",
2608+
e.what()));
2609+
return;
2610+
}
2611+
2612+
vRecv.SetVersion(version_orig);
25902613

25912614
if (!pfrom.RelayAddrsWithConn()) {
25922615
return;
@@ -2612,6 +2635,11 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
26122635
if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))
26132636
continue;
26142637

2638+
// Skip invalid addresses, maybe a new BIP155 network id from the future.
2639+
if (!addr.IsValid()) {
2640+
continue;
2641+
}
2642+
26152643
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
26162644
addr.nTime = nNow - 5 * 24 * 60 * 60;
26172645
pfrom.AddAddressKnown(addr);
@@ -2637,6 +2665,11 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
26372665
return;
26382666
}
26392667

2668+
if (msg_type == NetMsgType::SENDADDRv2) {
2669+
pfrom.m_wants_addrv2 = true;
2670+
return;
2671+
}
2672+
26402673
if (msg_type == NetMsgType::SENDHEADERS) {
26412674
LOCK(cs_main);
26422675
State(pfrom.GetId())->fPreferHeaders = true;
@@ -4134,6 +4167,7 @@ bool PeerManager::SendMessages(CNode* pto)
41344167
std::vector<CAddress> vAddr;
41354168
vAddr.reserve(pto->vAddrToSend.size());
41364169
assert(pto->m_addr_known);
4170+
const auto& msg_type = pto->m_wants_addrv2 ? NetMsgType::ADDRv2 : NetMsgType::ADDR;
41374171
for (const CAddress& addr : pto->vAddrToSend)
41384172
{
41394173
if (!pto->m_addr_known->contains(addr.GetKey()))
@@ -4143,14 +4177,14 @@ bool PeerManager::SendMessages(CNode* pto)
41434177
// receiver rejects addr messages larger than MAX_ADDR_TO_SEND
41444178
if (vAddr.size() >= MAX_ADDR_TO_SEND)
41454179
{
4146-
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
4180+
m_connman.PushMessage(pto, msgMaker.Make(msg_type, vAddr));
41474181
vAddr.clear();
41484182
}
41494183
}
41504184
}
41514185
pto->vAddrToSend.clear();
41524186
if (!vAddr.empty())
4153-
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr));
4187+
m_connman.PushMessage(pto, msgMaker.Make(msg_type, vAddr));
41544188
// we only send the big addr message once
41554189
if (pto->vAddrToSend.capacity() > 40)
41564190
pto->vAddrToSend.shrink_to_fit();

src/netaddress.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,25 @@ bool CNetAddr::IsInternal() const
476476
return m_net == NET_INTERNAL;
477477
}
478478

479+
bool CNetAddr::IsAddrV1Compatible() const
480+
{
481+
switch (m_net) {
482+
case NET_IPV4:
483+
case NET_IPV6:
484+
case NET_INTERNAL:
485+
return true;
486+
case NET_ONION:
487+
return m_addr.size() == ADDR_TORV2_SIZE;
488+
case NET_I2P:
489+
case NET_CJDNS:
490+
case NET_UNROUTABLE:
491+
case NET_MAX:
492+
return false;
493+
}
494+
495+
return false;
496+
}
497+
479498
enum Network CNetAddr::GetNetwork() const
480499
{
481500
if (IsInternal())
@@ -746,9 +765,12 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co
746765

747766
std::vector<unsigned char> CNetAddr::GetAddrBytes() const
748767
{
749-
uint8_t serialized[V1_SERIALIZATION_SIZE];
750-
SerializeV1Array(serialized);
751-
return {std::begin(serialized), std::end(serialized)};
768+
if (IsAddrV1Compatible()) {
769+
uint8_t serialized[V1_SERIALIZATION_SIZE];
770+
SerializeV1Array(serialized);
771+
return {std::begin(serialized), std::end(serialized)};
772+
}
773+
return std::vector<unsigned char>(m_addr.begin(), m_addr.end());
752774
}
753775

754776
uint64_t CNetAddr::GetHash() const

src/netaddress.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ class CNetAddr
173173
bool IsRoutable() const;
174174
bool IsInternal() const;
175175
bool IsValid() const;
176+
177+
/**
178+
* Check if the current object can be serialized in pre-ADDRv2/BIP155 format.
179+
*/
180+
bool IsAddrV1Compatible() const;
181+
176182
enum Network GetNetwork() const;
177183
std::string ToString() const;
178184
std::string ToStringIP() const;

src/netmessagemaker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class CNetMsgMaker
1818
CSerializedNetMsg Make(int nFlags, std::string msg_type, Args&&... args) const
1919
{
2020
CSerializedNetMsg msg;
21+
if (msg_type == NetMsgType::ADDRv2) {
22+
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
23+
// serialize methods produce an address in v2 format.
24+
nFlags |= ADDRV2_FORMAT;
25+
}
2126
msg.m_type = std::move(msg_type);
2227
CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
2328
return msg;

src/protocol.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace NetMsgType {
1414
const char *VERSION="version";
1515
const char *VERACK="verack";
1616
const char *ADDR="addr";
17+
const char *ADDRv2="addrv2";
18+
const char *SENDADDRv2="sendaddrv2";
1719
const char *INV="inv";
1820
const char *GETDATA="getdata";
1921
const char *MERKLEBLOCK="merkleblock";
@@ -52,6 +54,8 @@ const static std::string allNetMessageTypes[] = {
5254
NetMsgType::VERSION,
5355
NetMsgType::VERACK,
5456
NetMsgType::ADDR,
57+
NetMsgType::ADDRv2,
58+
NetMsgType::SENDADDRv2,
5559
NetMsgType::INV,
5660
NetMsgType::GETDATA,
5761
NetMsgType::MERKLEBLOCK,

src/protocol.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ extern const char* VERACK;
7676
* network.
7777
*/
7878
extern const char* ADDR;
79+
/**
80+
* The addrv2 message relays connection information for peers on the network just
81+
* like the addr message, but is extended to allow gossiping of longer node
82+
* addresses (see BIP155).
83+
*/
84+
extern const char *ADDRv2;
85+
/**
86+
* The sendaddrv2 message signals support for receiving ADDRv2 messages (BIP155).
87+
* It also implies that its sender can encode as ADDRv2 and would send ADDRv2
88+
* instead of ADDR to a peer that has signaled ADDRv2 support by sending SENDADDRv2.
89+
*/
90+
extern const char *SENDADDRv2;
7991
/**
8092
* The inv message (inventory message) transmits one or more inventories of
8193
* objects known to the transmitting peer.

src/test/net_tests.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
242242
BOOST_REQUIRE(addr.IsIPv4());
243243

244244
BOOST_CHECK(addr.IsBindAny());
245+
BOOST_CHECK(addr.IsAddrV1Compatible());
245246
BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0");
246247

247248
// IPv4, INADDR_NONE
@@ -250,6 +251,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
250251
BOOST_REQUIRE(addr.IsIPv4());
251252

252253
BOOST_CHECK(!addr.IsBindAny());
254+
BOOST_CHECK(addr.IsAddrV1Compatible());
253255
BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255");
254256

255257
// IPv4, casual
@@ -258,6 +260,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
258260
BOOST_REQUIRE(addr.IsIPv4());
259261

260262
BOOST_CHECK(!addr.IsBindAny());
263+
BOOST_CHECK(addr.IsAddrV1Compatible());
261264
BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78");
262265

263266
// IPv6, in6addr_any
@@ -266,6 +269,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
266269
BOOST_REQUIRE(addr.IsIPv6());
267270

268271
BOOST_CHECK(addr.IsBindAny());
272+
BOOST_CHECK(addr.IsAddrV1Compatible());
269273
BOOST_CHECK_EQUAL(addr.ToString(), "::");
270274

271275
// IPv6, casual
@@ -274,6 +278,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
274278
BOOST_REQUIRE(addr.IsIPv6());
275279

276280
BOOST_CHECK(!addr.IsBindAny());
281+
BOOST_CHECK(addr.IsAddrV1Compatible());
277282
BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff");
278283

279284
// TORv2
@@ -282,6 +287,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
282287
BOOST_REQUIRE(addr.IsTor());
283288

284289
BOOST_CHECK(!addr.IsBindAny());
290+
BOOST_CHECK(addr.IsAddrV1Compatible());
285291
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
286292

287293
// TORv3
@@ -291,6 +297,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
291297
BOOST_REQUIRE(addr.IsTor());
292298

293299
BOOST_CHECK(!addr.IsBindAny());
300+
BOOST_CHECK(!addr.IsAddrV1Compatible());
294301
BOOST_CHECK_EQUAL(addr.ToString(), torv3_addr);
295302

296303
// TORv3, broken, with wrong checksum
@@ -315,6 +322,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
315322
BOOST_REQUIRE(addr.IsInternal());
316323

317324
BOOST_CHECK(!addr.IsBindAny());
325+
BOOST_CHECK(addr.IsAddrV1Compatible());
318326
BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal");
319327

320328
// Totally bogus

test/functional/p2p_addr_relay.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,20 @@
3030

3131

3232
class AddrReceiver(P2PInterface):
33-
def on_addr(self, message):
33+
addrv2_received_and_checked = False
34+
35+
def __init__(self):
36+
super().__init__(support_addrv2 = True)
37+
38+
def on_addrv2(self, message):
3439
for addr in message.addrs:
3540
assert_equal(addr.nServices, 9)
3641
assert addr.ip.startswith('123.123.123.')
3742
assert (8333 <= addr.port < 8343)
43+
self.addrv2_received_and_checked = True
44+
45+
def wait_for_addrv2(self):
46+
self.wait_until(lambda: "addrv2" in self.last_message)
3847

3948

4049
class AddrTest(BitcoinTestFramework):
@@ -58,11 +67,13 @@ def run_test(self):
5867
with self.nodes[0].assert_debug_log([
5968
'Added 10 addresses from 127.0.0.1: 0 tried',
6069
'received: addr (301 bytes) peer=0',
61-
'sending addr (301 bytes) peer=1',
70+
'sending addrv2 (131 bytes) peer=1',
6271
]):
6372
addr_source.send_and_ping(msg)
6473
self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
65-
addr_receiver.sync_with_ping()
74+
addr_receiver.wait_for_addrv2()
75+
76+
assert addr_receiver.addrv2_received_and_checked
6677

6778

6879
if __name__ == '__main__':

0 commit comments

Comments
 (0)