/ test / functional / p2p_dns_seeds.py
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()