Skip to content

Commit b103fdc

Browse files
author
MarcoFalke
committed
Merge #19763: net: don't try to relay to the address' originator
7fabe0f net: don't relay to the address' originator (Vasil Dimov) Pull request description: For each address to be relayed we "randomly" pick 2 nodes to send the address to (in `RelayAddress()`). However we do not take into consideration that it does not make sense to relay the address back to its originator (`CNode::PushAddress()` will do nothing in that case). This means that if the originator is among the "randomly" picked nodes, then we will relay to one node less than intended. Fix this by skipping the originating node when choosing candidates to relay to. ACKs for top commit: sdaftuar: ACK 7fabe0f (this time I looked at the test, and verified the test breaks in expected ways if I break the code). jnewbery: utACK 7fabe0f (only net_processing changes. I haven't reviewed the test changes) jonatack: re-ACK 7fabe0f per `git range-diff b76abae fd897f8 7fabe0f`, change since last review is rebase and more readable Doxygen documentation Tree-SHA512: c6a9d11c7afc97ab4e8960513f6416648d4a8c0c64b713c145a7482a7b9e54946f81386a3351e3ec0011e5594ba5ccff4d10c6f656bb80680d9f0d0a63366165
2 parents eec9366 + 7fabe0f commit b103fdc

File tree

2 files changed

+48
-13
lines changed

2 files changed

+48
-13
lines changed

src/net_processing.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,7 +1410,23 @@ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman&
14101410
});
14111411
}
14121412

1413-
static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman)
1413+
/**
1414+
* Relay (gossip) an address to a few randomly chosen nodes.
1415+
* We choose the same nodes within a given 24h window (if the list of connected
1416+
* nodes does not change) and we don't relay to nodes that already know an
1417+
* address. So within 24h we will likely relay a given address once. This is to
1418+
* prevent a peer from unjustly giving their address better propagation by sending
1419+
* it to us repeatedly.
1420+
* @param[in] originator The peer that sent us the address. We don't want to relay it back.
1421+
* @param[in] addr Address to relay.
1422+
* @param[in] fReachable Whether the address' network is reachable. We relay unreachable
1423+
* addresses less.
1424+
* @param[in] connman Connection manager to choose nodes to relay to.
1425+
*/
1426+
static void RelayAddress(const CNode& originator,
1427+
const CAddress& addr,
1428+
bool fReachable,
1429+
const CConnman& connman)
14141430
{
14151431
if (!fReachable && !addr.IsRelayable()) return;
14161432

@@ -1427,8 +1443,8 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman&
14271443
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
14281444
assert(nRelayNodes <= best.size());
14291445

1430-
auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
1431-
if (pnode->RelayAddrsWithConn()) {
1446+
auto sortfunc = [&best, &hasher, nRelayNodes, &originator](CNode* pnode) {
1447+
if (pnode->RelayAddrsWithConn() && pnode != &originator) {
14321448
uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
14331449
for (unsigned int i = 0; i < nRelayNodes; i++) {
14341450
if (hashKey > best[i].first) {
@@ -2570,7 +2586,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
25702586
if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
25712587
{
25722588
// Relay to a limited number of other nodes
2573-
RelayAddress(addr, fReachable, m_connman);
2589+
RelayAddress(pfrom, addr, fReachable, m_connman);
25742590
}
25752591
// Do not store addresses outside our network
25762592
if (fReachable)

test/functional/p2p_addr_relay.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
)
2020
import time
2121

22+
# Keep this with length <= 10. Addresses from larger messages are not relayed.
2223
ADDRS = []
23-
for i in range(10):
24+
num_ipv4_addrs = 10
25+
26+
for i in range(num_ipv4_addrs):
2427
addr = CAddress()
2528
addr.time = int(time.time()) + i
2629
addr.nServices = NODE_NETWORK | NODE_WITNESS
@@ -30,11 +33,15 @@
3033

3134

3235
class AddrReceiver(P2PInterface):
36+
num_ipv4_received = 0
37+
3338
def on_addr(self, message):
3439
for addr in message.addrs:
3540
assert_equal(addr.nServices, 9)
41+
if not 8333 <= addr.port < 8343:
42+
raise AssertionError("Invalid addr.port of {} (8333-8342 expected)".format(addr.port))
3643
assert addr.ip.startswith('123.123.123.')
37-
assert (8333 <= addr.port < 8343)
44+
self.num_ipv4_received += 1
3845

3946

4047
class AddrTest(BitcoinTestFramework):
@@ -48,21 +55,33 @@ def run_test(self):
4855
msg = msg_addr()
4956

5057
self.log.info('Send too-large addr message')
51-
msg.addrs = ADDRS * 101
58+
msg.addrs = ADDRS * 101 # more than 1000 addresses in one message
5259
with self.nodes[0].assert_debug_log(['addr message size = 1010']):
5360
addr_source.send_and_ping(msg)
5461

5562
self.log.info('Check that addr message content is relayed and added to addrman')
56-
addr_receiver = self.nodes[0].add_p2p_connection(AddrReceiver())
63+
num_receivers = 7
64+
receivers = []
65+
for _ in range(num_receivers):
66+
receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver()))
5767
msg.addrs = ADDRS
58-
with self.nodes[0].assert_debug_log([
59-
'Added 10 addresses from 127.0.0.1: 0 tried',
68+
with self.nodes[0].assert_debug_log(
69+
[
70+
'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs),
6071
'received: addr (301 bytes) peer=0',
61-
'sending addr (301 bytes) peer=1',
62-
]):
72+
]
73+
):
6374
addr_source.send_and_ping(msg)
6475
self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
65-
addr_receiver.sync_with_ping()
76+
for receiver in receivers:
77+
receiver.sync_with_ping()
78+
79+
total_ipv4_received = sum(r.num_ipv4_received for r in receivers)
80+
81+
# Every IPv4 address must be relayed to two peers, other than the
82+
# originating node (addr_source).
83+
ipv4_branching_factor = 2
84+
assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor)
6685

6786

6887
if __name__ == '__main__':

0 commit comments

Comments
 (0)