p2p_dns_seeds.py
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 """Test ThreadDNSAddressSeed logic for querying DNS seeds.""" 6 7 import itertools 8 9 from test_framework.p2p import P2PInterface 10 from test_framework.test_framework import BitcoinTestFramework 11 12 13 class P2PDNSSeeds(BitcoinTestFramework): 14 def set_test_params(self): 15 self.setup_clean_chain = True 16 self.num_nodes = 1 17 self.extra_args = [["-dnsseed=1"]] 18 19 def run_test(self): 20 self.init_arg_tests() 21 self.existing_outbound_connections_test() 22 self.existing_block_relay_connections_test() 23 self.force_dns_test() 24 self.wait_time_tests() 25 26 def init_arg_tests(self): 27 fakeaddr = "fakenodeaddr.fakedomain.invalid." 28 29 self.log.info("Check that setting -connect disables -dnsseed by default") 30 self.nodes[0].stop_node() 31 with self.nodes[0].assert_debug_log(expected_msgs=["DNS seeding disabled"]): 32 self.start_node(0, [f"-connect={fakeaddr}"]) 33 34 self.log.info("Check that running -connect and -dnsseed means DNS logic runs.") 35 with self.nodes[0].assert_debug_log(expected_msgs=["Loading addresses from DNS seed"], timeout=12): 36 self.restart_node(0, [f"-connect={fakeaddr}", "-dnsseed=1"]) 37 38 self.log.info("Check that running -forcednsseed and -dnsseed=0 throws an error.") 39 self.nodes[0].stop_node() 40 self.nodes[0].assert_start_raises_init_error( 41 expected_msg="Error: Cannot set -forcednsseed to true when setting -dnsseed to false.", 42 extra_args=["-forcednsseed=1", "-dnsseed=0"], 43 ) 44 45 self.log.info("Check that running -forcednsseed and -connect throws an error.") 46 # -connect soft sets -dnsseed to false, so throws the same error 47 self.nodes[0].stop_node() 48 self.nodes[0].assert_start_raises_init_error( 49 expected_msg="Error: Cannot set -forcednsseed to true when setting -dnsseed to false.", 50 extra_args=["-forcednsseed=1", f"-connect={fakeaddr}"], 51 ) 52 53 # Restore default bitcoind settings 54 self.restart_node(0) 55 56 def existing_outbound_connections_test(self): 57 # Make sure addrman is populated to enter the conditional where we 58 # delay and potentially skip DNS seeding. 59 self.nodes[0].addpeeraddress("192.0.0.8", 8333) 60 61 self.log.info("Check that we *do not* query DNS seeds if we have 2 outbound connections") 62 63 self.restart_node(0) 64 with self.nodes[0].assert_debug_log(expected_msgs=["P2P peers available. Skipped DNS seeding."], timeout=12): 65 for i in range(2): 66 self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="outbound-full-relay") 67 68 def existing_block_relay_connections_test(self): 69 # Make sure addrman is populated to enter the conditional where we 70 # delay and potentially skip DNS seeding. No-op when run after 71 # existing_outbound_connections_test. 72 self.nodes[0].addpeeraddress("192.0.0.8", 8333) 73 74 self.log.info("Check that we *do* query DNS seeds if we only have 2 block-relay-only connections") 75 76 self.restart_node(0) 77 with self.nodes[0].assert_debug_log(expected_msgs=["Loading addresses from DNS seed"], timeout=12): 78 # This mimics the "anchors" logic where nodes are likely to 79 # reconnect to block-relay-only connections on startup. 80 # Since we do not participate in addr relay with these connections, 81 # we still want to query the DNS seeds. 82 for i in range(2): 83 self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="block-relay-only") 84 85 def force_dns_test(self): 86 self.log.info("Check that we query DNS seeds if -forcednsseed param is set") 87 88 with self.nodes[0].assert_debug_log(expected_msgs=["Loading addresses from DNS seed"], timeout=12): 89 # -dnsseed defaults to 1 in bitcoind, but 0 in the test framework, 90 # so pass it explicitly here 91 self.restart_node(0, ["-forcednsseed", "-dnsseed=1"]) 92 93 # Restore default for subsequent tests 94 self.restart_node(0) 95 96 def wait_time_tests(self): 97 self.log.info("Check the delay before querying DNS seeds") 98 99 # Populate addrman with < 1000 addresses 100 for i in range(5): 101 a = f"192.0.0.{i}" 102 self.nodes[0].addpeeraddress(a, 8333) 103 104 # The delay should be 11 seconds 105 with self.nodes[0].assert_debug_log(expected_msgs=["Waiting 11 seconds before querying DNS seeds.\n"]): 106 self.restart_node(0) 107 108 # Populate addrman with > 1000 addresses 109 for i in itertools.count(): 110 first_octet = i % 2 + 1 111 second_octet = i % 256 112 third_octet = i % 100 113 a = f"{first_octet}.{second_octet}.{third_octet}.1" 114 self.nodes[0].addpeeraddress(a, 8333) 115 if (i > 1000 and i % 100 == 0): 116 # The addrman size is non-deterministic because new addresses 117 # are sorted into buckets, potentially displacing existing 118 # addresses. Periodically check if we have met the desired 119 # threshold. 120 if len(self.nodes[0].getnodeaddresses(0)) > 1000: 121 break 122 123 # The delay should be 5 mins 124 with self.nodes[0].assert_debug_log(expected_msgs=["Waiting 300 seconds before querying DNS seeds.\n"]): 125 self.restart_node(0) 126 127 128 if __name__ == '__main__': 129 P2PDNSSeeds().main()