Skip to content

Commit 0a0a95b

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#21707: test: Extend functional tests for addr relay
a732ee3 [test] Add tests for addr relay in -blocksonly mode (Amiti Uttarwar) a6694ea [test] Add address relay tests involving outbound peers (Martin Zumsande) 8188b77 [test] Add tests for getaddr behavior (Martin Zumsande) d2dbfe6 [test] Extract sending an addr message into a helper (Amiti Uttarwar) c991943 [test] Refactor the addr relay test to prepare for new tests (Amiti Uttarwar) Pull request description: This extends the functional test `p2p_addr_relay.py`. It adds test coverage for address relay involving outbound peers, tests for both outgoing and incoming `GETADDR` requests and tests for `-blocksonly` mode. The initial refactors and some of the new tests were taken from Amiti Uttarwar's PR #21528 - they are general test improvements not directly tied to the change proposed there. ACKs for top commit: amitiuttarwar: re-ACK a732ee3, small diff based on code review MarcoFalke: Concept ACK a732ee3 🌊 Tree-SHA512: e80d52683808ddd6b948a5134239f002f3fecf61b60e187877b07be6251721fde847104e495c75a1a5133a09c0b41a9255a0bec82932c0b304b516fa89bce33e
2 parents c4571a0 + a732ee3 commit 0a0a95b

File tree

1 file changed

+151
-22
lines changed

1 file changed

+151
-22
lines changed

test/functional/p2p_addr_relay.py

Lines changed: 151 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
NODE_NETWORK,
1212
NODE_WITNESS,
1313
msg_addr,
14+
msg_getaddr
1415
)
1516
from test_framework.p2p import P2PInterface
1617
from test_framework.test_framework import BitcoinTestFramework
@@ -19,18 +20,6 @@
1920
)
2021
import time
2122

22-
# Keep this with length <= 10. Addresses from larger messages are not relayed.
23-
ADDRS = []
24-
num_ipv4_addrs = 10
25-
26-
for i in range(num_ipv4_addrs):
27-
addr = CAddress()
28-
addr.time = int(time.time()) + i
29-
addr.nServices = NODE_NETWORK | NODE_WITNESS
30-
addr.ip = "123.123.123.{}".format(i % 256)
31-
addr.port = 8333 + i
32-
ADDRS.append(addr)
33-
3423

3524
class AddrReceiver(P2PInterface):
3625
num_ipv4_received = 0
@@ -44,36 +33,87 @@ def on_addr(self, message):
4433
self.num_ipv4_received += 1
4534

4635

36+
class GetAddrStore(P2PInterface):
37+
getaddr_received = False
38+
num_ipv4_received = 0
39+
40+
def on_getaddr(self, message):
41+
self.getaddr_received = True
42+
43+
def on_addr(self, message):
44+
for addr in message.addrs:
45+
self.num_ipv4_received += 1
46+
47+
def addr_received(self):
48+
return self.num_ipv4_received != 0
49+
50+
4751
class AddrTest(BitcoinTestFramework):
52+
counter = 0
53+
mocktime = int(time.time())
54+
4855
def set_test_params(self):
4956
self.num_nodes = 1
5057

5158
def run_test(self):
52-
self.log.info('Create connection that sends addr messages')
53-
addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
59+
self.oversized_addr_test()
60+
self.relay_tests()
61+
self.getaddr_tests()
62+
self.blocksonly_mode_tests()
63+
64+
def setup_addr_msg(self, num):
65+
addrs = []
66+
for i in range(num):
67+
addr = CAddress()
68+
addr.time = self.mocktime + i
69+
addr.nServices = NODE_NETWORK | NODE_WITNESS
70+
addr.ip = f"123.123.123.{self.counter % 256}"
71+
addr.port = 8333 + i
72+
addrs.append(addr)
73+
self.counter += 1
74+
5475
msg = msg_addr()
76+
msg.addrs = addrs
77+
return msg
78+
79+
def send_addr_msg(self, source, msg, receivers):
80+
source.send_and_ping(msg)
81+
# pop m_next_addr_send timer
82+
self.mocktime += 5 * 60
83+
self.nodes[0].setmocktime(self.mocktime)
84+
for peer in receivers:
85+
peer.sync_with_ping()
5586

56-
self.log.info('Send too-large addr message')
57-
msg.addrs = ADDRS * 101 # more than 1000 addresses in one message
87+
def oversized_addr_test(self):
88+
self.log.info('Send an addr message that is too large')
89+
addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
90+
91+
msg = self.setup_addr_msg(1010)
5892
with self.nodes[0].assert_debug_log(['addr message size = 1010']):
5993
addr_source.send_and_ping(msg)
6094

95+
self.nodes[0].disconnect_p2ps()
96+
97+
def relay_tests(self):
98+
self.log.info('Test address relay')
6199
self.log.info('Check that addr message content is relayed and added to addrman')
100+
addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
62101
num_receivers = 7
63102
receivers = []
64103
for _ in range(num_receivers):
65104
receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver()))
66-
msg.addrs = ADDRS
105+
106+
# Keep this with length <= 10. Addresses from larger messages are not
107+
# relayed.
108+
num_ipv4_addrs = 10
109+
msg = self.setup_addr_msg(num_ipv4_addrs)
67110
with self.nodes[0].assert_debug_log(
68111
[
69112
'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs),
70-
'received: addr (301 bytes) peer=0',
113+
'received: addr (301 bytes) peer=1',
71114
]
72115
):
73-
addr_source.send_and_ping(msg)
74-
self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
75-
for receiver in receivers:
76-
receiver.sync_with_ping()
116+
self.send_addr_msg(addr_source, msg, receivers)
77117

78118
total_ipv4_received = sum(r.num_ipv4_received for r in receivers)
79119

@@ -82,6 +122,95 @@ def run_test(self):
82122
ipv4_branching_factor = 2
83123
assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor)
84124

125+
self.nodes[0].disconnect_p2ps()
126+
127+
self.log.info('Check relay of addresses received from outbound peers')
128+
inbound_peer = self.nodes[0].add_p2p_connection(AddrReceiver())
129+
full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
130+
msg = self.setup_addr_msg(2)
131+
self.send_addr_msg(full_outbound_peer, msg, [inbound_peer])
132+
self.log.info('Check that the first addr message received from an outbound peer is not relayed')
133+
# Currently, there is a flag that prevents the first addr message received
134+
# from a new outbound peer to be relayed to others. Originally meant to prevent
135+
# large GETADDR responses from being relayed, it now typically affects the self-announcement
136+
# of the outbound peer which is often sent before the GETADDR response.
137+
assert_equal(inbound_peer.num_ipv4_received, 0)
138+
139+
self.log.info('Check that subsequent addr messages sent from an outbound peer are relayed')
140+
msg2 = self.setup_addr_msg(2)
141+
self.send_addr_msg(full_outbound_peer, msg2, [inbound_peer])
142+
assert_equal(inbound_peer.num_ipv4_received, 2)
143+
144+
self.log.info('Check address relay to outbound peers')
145+
block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only")
146+
msg3 = self.setup_addr_msg(2)
147+
self.send_addr_msg(inbound_peer, msg3, [full_outbound_peer, block_relay_peer])
148+
149+
self.log.info('Check that addresses are relayed to full outbound peers')
150+
assert_equal(full_outbound_peer.num_ipv4_received, 2)
151+
self.log.info('Check that addresses are not relayed to block-relay-only outbound peers')
152+
assert_equal(block_relay_peer.num_ipv4_received, 0)
153+
154+
self.nodes[0].disconnect_p2ps()
155+
156+
def getaddr_tests(self):
157+
self.log.info('Test getaddr behavior')
158+
self.log.info('Check that we send a getaddr message upon connecting to an outbound-full-relay peer')
159+
full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
160+
full_outbound_peer.sync_with_ping()
161+
assert full_outbound_peer.getaddr_received
162+
163+
self.log.info('Check that we do not send a getaddr message upon connecting to a block-relay-only peer')
164+
block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only")
165+
block_relay_peer.sync_with_ping()
166+
assert_equal(block_relay_peer.getaddr_received, False)
167+
168+
self.log.info('Check that we answer getaddr messages only from inbound peers')
169+
inbound_peer = self.nodes[0].add_p2p_connection(GetAddrStore())
170+
inbound_peer.sync_with_ping()
171+
172+
# Add some addresses to addrman
173+
for i in range(1000):
174+
first_octet = i >> 8
175+
second_octet = i % 256
176+
a = f"{first_octet}.{second_octet}.1.1"
177+
self.nodes[0].addpeeraddress(a, 8333)
178+
179+
full_outbound_peer.send_and_ping(msg_getaddr())
180+
block_relay_peer.send_and_ping(msg_getaddr())
181+
inbound_peer.send_and_ping(msg_getaddr())
182+
183+
self.mocktime += 5 * 60
184+
self.nodes[0].setmocktime(self.mocktime)
185+
inbound_peer.wait_until(inbound_peer.addr_received)
186+
187+
assert_equal(full_outbound_peer.num_ipv4_received, 0)
188+
assert_equal(block_relay_peer.num_ipv4_received, 0)
189+
assert inbound_peer.num_ipv4_received > 100
190+
191+
self.nodes[0].disconnect_p2ps()
192+
193+
def blocksonly_mode_tests(self):
194+
self.log.info('Test addr relay in -blocksonly mode')
195+
self.restart_node(0, ["-blocksonly"])
196+
self.mocktime = int(time.time())
197+
198+
self.log.info('Check that we send getaddr messages')
199+
full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
200+
full_outbound_peer.sync_with_ping()
201+
assert full_outbound_peer.getaddr_received
202+
203+
self.log.info('Check that we relay address messages')
204+
addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
205+
msg = self.setup_addr_msg(2)
206+
addr_source.send_and_ping(msg)
207+
self.mocktime += 5 * 60
208+
self.nodes[0].setmocktime(self.mocktime)
209+
full_outbound_peer.sync_with_ping()
210+
assert_equal(full_outbound_peer.num_ipv4_received, 2)
211+
212+
self.nodes[0].disconnect_p2ps()
213+
85214

86215
if __name__ == '__main__':
87216
AddrTest().main()

0 commit comments

Comments
 (0)