From c9919433994924931757aa7ec278c50744ede35d Mon Sep 17 00:00:00 2001 From: Amiti Uttarwar Date: Mon, 29 Mar 2021 15:19:37 -0700 Subject: [PATCH 1/5] [test] Refactor the addr relay test to prepare for new tests Moves setting up the addr message into a repeatable function, and breaks up the existing tests into separate functions for legibility. --- test/functional/p2p_addr_relay.py | 59 ++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 69821763bdb..b728ed428bc 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -19,18 +19,6 @@ from test_framework.util import ( ) import time -# Keep this with length <= 10. Addresses from larger messages are not relayed. -ADDRS = [] -num_ipv4_addrs = 10 - -for i in range(num_ipv4_addrs): - addr = CAddress() - addr.time = int(time.time()) + i - addr.nServices = NODE_NETWORK | NODE_WITNESS - addr.ip = "123.123.123.{}".format(i % 256) - addr.port = 8333 + i - ADDRS.append(addr) - class AddrReceiver(P2PInterface): num_ipv4_received = 0 @@ -45,33 +33,62 @@ class AddrReceiver(P2PInterface): class AddrTest(BitcoinTestFramework): + counter = 0 + mocktime = int(time.time()) + def set_test_params(self): self.num_nodes = 1 def run_test(self): - self.log.info('Create connection that sends addr messages') - addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) - msg = msg_addr() + self.oversized_addr_test() + self.relay_tests() - self.log.info('Send too-large addr message') - msg.addrs = ADDRS * 101 # more than 1000 addresses in one message + def setup_addr_msg(self, num): + addrs = [] + for i in range(num): + addr = CAddress() + addr.time = self.mocktime + i + addr.nServices = NODE_NETWORK | NODE_WITNESS + addr.ip = f"123.123.123.{self.counter % 256}" + addr.port = 8333 + i + addrs.append(addr) + self.counter += 1 + + msg = msg_addr() + msg.addrs = addrs + return msg + + def oversized_addr_test(self): + self.log.info('Send an addr message that is too large') + addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) + + msg = self.setup_addr_msg(1010) with self.nodes[0].assert_debug_log(['addr message size = 1010']): addr_source.send_and_ping(msg) + self.nodes[0].disconnect_p2ps() + + def relay_tests(self): self.log.info('Check that addr message content is relayed and added to addrman') + addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) num_receivers = 7 receivers = [] for _ in range(num_receivers): receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver())) - msg.addrs = ADDRS + + # Keep this with length <= 10. Addresses from larger messages are not + # relayed. + num_ipv4_addrs = 10 + msg = self.setup_addr_msg(num_ipv4_addrs) with self.nodes[0].assert_debug_log( [ 'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs), - 'received: addr (301 bytes) peer=0', + 'received: addr (301 bytes) peer=1', ] ): addr_source.send_and_ping(msg) - self.nodes[0].setmocktime(int(time.time()) + 30 * 60) + self.mocktime += 30 * 60 + self.nodes[0].setmocktime(self.mocktime) for receiver in receivers: receiver.sync_with_ping() @@ -82,6 +99,8 @@ class AddrTest(BitcoinTestFramework): ipv4_branching_factor = 2 assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor) + self.nodes[0].disconnect_p2ps() + if __name__ == '__main__': AddrTest().main() From d2dbfe6ff1806e5248399b28a7a1a22dab726c40 Mon Sep 17 00:00:00 2001 From: Amiti Uttarwar Date: Tue, 30 Mar 2021 13:15:30 -0700 Subject: [PATCH 2/5] [test] Extract sending an addr message into a helper Also reduces mocktime to prevent idle disconnects Co-Authored-By: Martin Zumsande --- test/functional/p2p_addr_relay.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index b728ed428bc..4d7ad2eb107 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -58,6 +58,14 @@ class AddrTest(BitcoinTestFramework): msg.addrs = addrs return msg + def send_addr_msg(self, source, msg, receivers): + source.send_and_ping(msg) + # pop m_next_addr_send timer + self.mocktime += 5 * 60 + self.nodes[0].setmocktime(self.mocktime) + for peer in receivers: + peer.sync_with_ping() + def oversized_addr_test(self): self.log.info('Send an addr message that is too large') addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) @@ -86,11 +94,7 @@ class AddrTest(BitcoinTestFramework): 'received: addr (301 bytes) peer=1', ] ): - addr_source.send_and_ping(msg) - self.mocktime += 30 * 60 - self.nodes[0].setmocktime(self.mocktime) - for receiver in receivers: - receiver.sync_with_ping() + self.send_addr_msg(addr_source, msg, receivers) total_ipv4_received = sum(r.num_ipv4_received for r in receivers) From 8188b77c17d78bf608cb41978db4d0f46e91f7d8 Mon Sep 17 00:00:00 2001 From: Martin Zumsande Date: Fri, 16 Apr 2021 16:49:01 +0200 Subject: [PATCH 3/5] [test] Add tests for getaddr behavior Co-authored-by: Amiti Uttarwar --- test/functional/p2p_addr_relay.py | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 4d7ad2eb107..96f4ff8c2d0 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -11,6 +11,7 @@ from test_framework.messages import ( NODE_NETWORK, NODE_WITNESS, msg_addr, + msg_getaddr ) from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework @@ -32,6 +33,21 @@ class AddrReceiver(P2PInterface): self.num_ipv4_received += 1 +class GetAddrStore(P2PInterface): + getaddr_received = False + num_ipv4_received = 0 + + def on_getaddr(self, message): + self.getaddr_received = True + + def on_addr(self, message): + for addr in message.addrs: + self.num_ipv4_received += 1 + + def addr_received(self): + return self.num_ipv4_received != 0 + + class AddrTest(BitcoinTestFramework): counter = 0 mocktime = int(time.time()) @@ -42,6 +58,7 @@ class AddrTest(BitcoinTestFramework): def run_test(self): self.oversized_addr_test() self.relay_tests() + self.getaddr_tests() def setup_addr_msg(self, num): addrs = [] @@ -105,6 +122,42 @@ class AddrTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() + def getaddr_tests(self): + self.log.info('Test getaddr behavior') + self.log.info('Check that we send a getaddr message upon connecting to an outbound-full-relay peer') + full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay") + full_outbound_peer.sync_with_ping() + assert full_outbound_peer.getaddr_received + + self.log.info('Check that we do not send a getaddr message upon connecting to a block-relay-only peer') + block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only") + block_relay_peer.sync_with_ping() + assert_equal(block_relay_peer.getaddr_received, False) + + self.log.info('Check that we answer getaddr messages only from inbound peers') + inbound_peer = self.nodes[0].add_p2p_connection(GetAddrStore()) + inbound_peer.sync_with_ping() + # Add some addresses to addrman + for i in range(1000): + first_octet = i >> 8 + second_octet = i % 256 + a = f"{first_octet}.{second_octet}.1.1" + self.nodes[0].addpeeraddress(a, 8333) + + full_outbound_peer.send_and_ping(msg_getaddr()) + block_relay_peer.send_and_ping(msg_getaddr()) + inbound_peer.send_and_ping(msg_getaddr()) + + self.mocktime += 5 * 60 + self.nodes[0].setmocktime(self.mocktime) + inbound_peer.wait_until(inbound_peer.addr_received) + + assert_equal(full_outbound_peer.num_ipv4_received, 0) + assert_equal(block_relay_peer.num_ipv4_received, 0) + assert inbound_peer.num_ipv4_received > 100 + + self.nodes[0].disconnect_p2ps() + if __name__ == '__main__': AddrTest().main() From a6694eaed8f86a6ad79689bbcbfdbed4d73327c9 Mon Sep 17 00:00:00 2001 From: Martin Zumsande Date: Fri, 16 Apr 2021 17:53:15 +0200 Subject: [PATCH 4/5] [test] Add address relay tests involving outbound peers Co-authored-by: Amiti Uttarwar --- test/functional/p2p_addr_relay.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 96f4ff8c2d0..46c804e7289 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -94,6 +94,7 @@ class AddrTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() def relay_tests(self): + self.log.info('Test address relay') self.log.info('Check that addr message content is relayed and added to addrman') addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) num_receivers = 7 @@ -122,6 +123,35 @@ class AddrTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() + self.log.info('Check relay of addresses received from outbound peers') + inbound_peer = self.nodes[0].add_p2p_connection(AddrReceiver()) + full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay") + msg = self.setup_addr_msg(2) + self.send_addr_msg(full_outbound_peer, msg, [inbound_peer]) + self.log.info('Check that the first addr message received from an outbound peer is not relayed') + # Currently, there is a flag that prevents the first addr message received + # from a new outbound peer to be relayed to others. Originally meant to prevent + # large GETADDR responses from being relayed, it now typically affects the self-announcement + # of the outbound peer which is often sent before the GETADDR response. + assert_equal(inbound_peer.num_ipv4_received, 0) + + self.log.info('Check that subsequent addr messages sent from an outbound peer are relayed') + msg2 = self.setup_addr_msg(2) + self.send_addr_msg(full_outbound_peer, msg2, [inbound_peer]) + assert_equal(inbound_peer.num_ipv4_received, 2) + + self.log.info('Check address relay to outbound peers') + block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only") + msg3 = self.setup_addr_msg(2) + self.send_addr_msg(inbound_peer, msg3, [full_outbound_peer, block_relay_peer]) + + self.log.info('Check that addresses are relayed to full outbound peers') + assert_equal(full_outbound_peer.num_ipv4_received, 2) + self.log.info('Check that addresses are not relayed to block-relay-only outbound peers') + assert_equal(block_relay_peer.num_ipv4_received, 0) + + self.nodes[0].disconnect_p2ps() + def getaddr_tests(self): self.log.info('Test getaddr behavior') self.log.info('Check that we send a getaddr message upon connecting to an outbound-full-relay peer') From a732ee353c1922a1f9ca082775884d190893e0e9 Mon Sep 17 00:00:00 2001 From: Amiti Uttarwar Date: Thu, 15 Apr 2021 23:09:40 +0200 Subject: [PATCH 5/5] [test] Add tests for addr relay in -blocksonly mode Co-Authored-By: Martin Zumsande --- test/functional/p2p_addr_relay.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 46c804e7289..fdd02b73249 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -59,6 +59,7 @@ class AddrTest(BitcoinTestFramework): self.oversized_addr_test() self.relay_tests() self.getaddr_tests() + self.blocksonly_mode_tests() def setup_addr_msg(self, num): addrs = [] @@ -167,6 +168,7 @@ class AddrTest(BitcoinTestFramework): self.log.info('Check that we answer getaddr messages only from inbound peers') inbound_peer = self.nodes[0].add_p2p_connection(GetAddrStore()) inbound_peer.sync_with_ping() + # Add some addresses to addrman for i in range(1000): first_octet = i >> 8 @@ -188,6 +190,27 @@ class AddrTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() + def blocksonly_mode_tests(self): + self.log.info('Test addr relay in -blocksonly mode') + self.restart_node(0, ["-blocksonly"]) + self.mocktime = int(time.time()) + + self.log.info('Check that we send getaddr messages') + full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay") + full_outbound_peer.sync_with_ping() + assert full_outbound_peer.getaddr_received + + self.log.info('Check that we relay address messages') + addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) + msg = self.setup_addr_msg(2) + addr_source.send_and_ping(msg) + self.mocktime += 5 * 60 + self.nodes[0].setmocktime(self.mocktime) + full_outbound_peer.sync_with_ping() + assert_equal(full_outbound_peer.num_ipv4_received, 2) + + self.nodes[0].disconnect_p2ps() + if __name__ == '__main__': AddrTest().main()