Skip to content

Commit cb352c5

Browse files
Merge dashpay#5884: backport: Merge bitcoin#22423, 22096
6d44f36 Merge bitcoin#22096: p2p: AddrFetch - don't disconnect on self-announcements (fanquake) Pull request description: bitcoin backports Top commit has no ACKs. Tree-SHA512: 0a7def9eedeab85f4fb7a34e88ce7c051e3e97b7ec68cb91d02e3387de65d0756e11f0d53c66b8d6a2c886f67649b7887349ea48aaf1dd3af86e4e1ca81c29f1
2 parents e4c848b + 6d44f36 commit cb352c5

File tree

7 files changed

+95
-9
lines changed

7 files changed

+95
-9
lines changed

src/net.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,16 +1296,29 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
12961296

12971297
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
12981298
{
1299-
if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false;
1300-
1301-
const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay;
1299+
std::optional<int> max_connections;
1300+
switch (conn_type) {
1301+
case ConnectionType::INBOUND:
1302+
case ConnectionType::MANUAL:
1303+
case ConnectionType::FEELER:
1304+
return false;
1305+
case ConnectionType::OUTBOUND_FULL_RELAY:
1306+
max_connections = m_max_outbound_full_relay;
1307+
break;
1308+
case ConnectionType::BLOCK_RELAY:
1309+
max_connections = m_max_outbound_block_relay;
1310+
break;
1311+
// no limit for ADDR_FETCH because -seednode has no limit either
1312+
case ConnectionType::ADDR_FETCH:
1313+
break;
1314+
} // no default case, so the compiler can warn about missing cases
13021315

13031316
// Count existing connections
13041317
int existing_connections = WITH_LOCK(m_nodes_mutex,
13051318
return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
13061319

13071320
// Max connections of specified type already exist
1308-
if (existing_connections >= max_connections) return false;
1321+
if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
13091322

13101323
// Max total outbound connections already exist
13111324
CSemaphoreGrant grant(*semOutbound, true);

src/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@ friend class CNode;
11061106
*
11071107
* @param[in] address Address of node to try connecting to
11081108
* @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY
1109+
* or ConnectionType::ADDR_FETCH
11091110
* @return bool Returns false if there are no available
11101111
* slots for this connection:
11111112
* - conn_type not a supported ConnectionType

src/net_processing.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3657,7 +3657,9 @@ void PeerManagerImpl::ProcessMessage(
36573657

36583658
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
36593659
if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
3660-
if (pfrom.IsAddrFetchConn()) {
3660+
3661+
// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
3662+
if (pfrom.IsAddrFetchConn() && vAddr.size() > 1) {
36613663
LogPrint(BCLog::NET_NETCONN, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
36623664
pfrom.fDisconnect = true;
36633665
}
@@ -5351,6 +5353,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
53515353

53525354
const auto current_time = GetTime<std::chrono::microseconds>();
53535355

5356+
if (pto->IsAddrFetchConn() && current_time - std::chrono::seconds(pto->nTimeConnected) > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) {
5357+
LogPrint(BCLog::NET_NETCONN, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId());
5358+
pto->fDisconnect = true;
5359+
return true;
5360+
}
5361+
53545362
MaybeSendPing(*pto, *peer, current_time);
53555363

53565364
// MaybeSendPing may have marked peer for disconnection

src/rpc/net.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ static RPCHelpMan addconnection()
352352
"\nOpen an outbound connection to a specified node. This RPC is for testing only.\n",
353353
{
354354
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},
355-
{"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."},
355+
{"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open (\"outbound-full-relay\", \"block-relay-only\" or \"addr-fetch\")."},
356356
},
357357
RPCResult{
358358
RPCResult::Type::OBJ, "", "",
@@ -378,6 +378,8 @@ static RPCHelpMan addconnection()
378378
conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
379379
} else if (conn_type_in == "block-relay-only") {
380380
conn_type = ConnectionType::BLOCK_RELAY;
381+
} else if (conn_type_in == "addr-fetch") {
382+
conn_type = ConnectionType::ADDR_FETCH;
381383
} else {
382384
throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
383385
}

test/functional/p2p_addrfetch.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2021 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""
6+
Test p2p addr-fetch connections
7+
"""
8+
9+
import time
10+
11+
from test_framework.messages import msg_addr, CAddress, NODE_NETWORK
12+
from test_framework.p2p import P2PInterface, p2p_lock
13+
from test_framework.test_framework import BitcoinTestFramework
14+
from test_framework.util import assert_equal
15+
16+
ADDR = CAddress()
17+
ADDR.time = int(time.time())
18+
ADDR.nServices = NODE_NETWORK
19+
ADDR.ip = "192.0.0.8"
20+
ADDR.port = 18444
21+
22+
23+
class P2PAddrFetch(BitcoinTestFramework):
24+
25+
def set_test_params(self):
26+
self.setup_clean_chain = True
27+
self.num_nodes = 1
28+
29+
def run_test(self):
30+
node = self.nodes[0]
31+
self.log.info("Connect to an addr-fetch peer")
32+
peer = node.add_outbound_p2p_connection(P2PInterface(), p2p_idx=0, connection_type="addr-fetch")
33+
info = node.getpeerinfo()
34+
assert_equal(len(info), 1)
35+
assert_equal(info[0]['connection_type'], 'addr-fetch')
36+
37+
self.log.info("Check that we send getaddr but don't try to sync headers with the addr-fetch peer")
38+
peer.sync_send_with_ping()
39+
with p2p_lock:
40+
assert peer.message_count['getaddr'] == 1
41+
assert peer.message_count['getheaders'] == 0
42+
43+
self.log.info("Check that answering the getaddr with a single address does not lead to disconnect")
44+
# This prevents disconnecting on self-announcements
45+
msg = msg_addr()
46+
msg.addrs = [ADDR]
47+
peer.send_and_ping(msg)
48+
assert_equal(len(node.getpeerinfo()), 1)
49+
50+
self.log.info("Check that answering with larger addr messages leads to disconnect")
51+
msg.addrs = [ADDR] * 2
52+
peer.send_message(msg)
53+
peer.wait_for_disconnect(timeout=5)
54+
55+
self.log.info("Check timeout for addr-fetch peer that does not send addrs")
56+
peer = node.add_outbound_p2p_connection(P2PInterface(), p2p_idx=1, connection_type="addr-fetch")
57+
node.setmocktime(int(time.time()) + 301) # Timeout: 5 minutes
58+
peer.wait_for_disconnect(timeout=5)
59+
60+
61+
if __name__ == '__main__':
62+
P2PAddrFetch().main()

test/functional/test_framework/test_node.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,8 @@ def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
571571
return p2p_conn
572572

573573
def add_outbound_p2p_connection(self, p2p_conn, *, p2p_idx, connection_type="outbound-full-relay", **kwargs):
574-
"""Add an outbound p2p connection from node. Either
575-
full-relay("outbound-full-relay") or
576-
block-relay-only("block-relay-only") connection.
574+
"""Add an outbound p2p connection from node. Must be an
575+
"outbound-full-relay", "block-relay-only" or "addr-fetch" connection.
577576
578577
This method adds the p2p connection to the self.p2ps list and returns
579578
the connection to the caller.

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
'p2p_addr_relay.py',
208208
'p2p_getaddr_caching.py',
209209
'p2p_getdata.py',
210+
'p2p_addrfetch.py',
210211
'rpc_net.py',
211212
'wallet_keypool.py --legacy-wallet',
212213
'wallet_keypool_hd.py --legacy-wallet',

0 commit comments

Comments
 (0)