p2p_add_connections.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2020-present 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 add_outbound_p2p_connection test framework functionality"""
   6  
   7  from test_framework.p2p import P2PInterface
   8  from test_framework.test_framework import BitcoinTestFramework
   9  from test_framework.util import (
  10      assert_equal,
  11      check_node_connections,
  12  )
  13  
  14  
  15  class VersionSender(P2PInterface):
  16      def on_open(self):
  17          assert self.on_connection_send_msg is not None
  18          self.send_version()
  19          assert self.on_connection_send_msg is None
  20  
  21  
  22  class P2PFeelerReceiver(P2PInterface):
  23      def on_version(self, message):
  24          # The bitcoind node closes feeler connections as soon as a version
  25          # message is received from the test framework. Don't send any responses
  26          # to the node's version message since the connection will already be
  27          # closed.
  28          self.send_version()
  29  
  30  class P2PAddConnections(BitcoinTestFramework):
  31      def set_test_params(self):
  32          self.num_nodes = 2
  33  
  34      def setup_network(self):
  35          self.setup_nodes()
  36          # Don't connect the nodes
  37  
  38      def run_test(self):
  39          self.log.info("Add 8 outbounds to node 0")
  40          for i in range(8):
  41              self.log.info(f"outbound: {i}")
  42              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="outbound-full-relay")
  43  
  44          self.log.info("Add 2 block-relay-only connections to node 0")
  45          for i in range(2):
  46              self.log.info(f"block-relay-only: {i}")
  47              # set p2p_idx based on the outbound connections already open to the
  48              # node, so add 8 to account for the previous full-relay connections
  49              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")
  50  
  51          self.log.info("Add 2 block-relay-only connections to node 1")
  52          for i in range(2):
  53              self.log.info(f"block-relay-only: {i}")
  54              self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="block-relay-only")
  55  
  56          self.log.info("Add 5 inbound connections to node 1")
  57          for i in range(5):
  58              self.log.info(f"inbound: {i}")
  59              self.nodes[1].add_p2p_connection(P2PInterface())
  60  
  61          self.log.info("Add 8 outbounds to node 1")
  62          for i in range(8):
  63              self.log.info(f"outbound: {i}")
  64              # bump p2p_idx to account for the 2 existing outbounds on node 1
  65              self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 2)
  66  
  67          self.log.info("Check the connections opened as expected")
  68          check_node_connections(node=self.nodes[0], num_in=0, num_out=10)
  69          check_node_connections(node=self.nodes[1], num_in=5, num_out=10)
  70  
  71          self.log.info("Disconnect p2p connections & try to re-open")
  72          self.nodes[0].disconnect_p2ps()
  73          check_node_connections(node=self.nodes[0], num_in=0, num_out=0)
  74  
  75          self.log.info("Add 8 outbounds to node 0")
  76          for i in range(8):
  77              self.log.info(f"outbound: {i}")
  78              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)
  79          check_node_connections(node=self.nodes[0], num_in=0, num_out=8)
  80  
  81          self.log.info("Add 2 block-relay-only connections to node 0")
  82          for i in range(2):
  83              self.log.info(f"block-relay-only: {i}")
  84              # bump p2p_idx to account for the 8 existing outbounds on node 0
  85              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")
  86          check_node_connections(node=self.nodes[0], num_in=0, num_out=10)
  87  
  88          self.log.info("Restart node 0 and try to reconnect to p2ps")
  89          self.restart_node(0)
  90  
  91          self.log.info("Add 4 outbounds to node 0")
  92          for i in range(4):
  93              self.log.info(f"outbound: {i}")
  94              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)
  95          check_node_connections(node=self.nodes[0], num_in=0, num_out=4)
  96  
  97          self.log.info("Add 2 block-relay-only connections to node 0")
  98          for i in range(2):
  99              self.log.info(f"block-relay-only: {i}")
 100              # bump p2p_idx to account for the 4 existing outbounds on node 0
 101              self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 4, connection_type="block-relay-only")
 102          check_node_connections(node=self.nodes[0], num_in=0, num_out=6)
 103  
 104          check_node_connections(node=self.nodes[1], num_in=5, num_out=10)
 105  
 106          self.log.info("Add 1 feeler connection to node 0")
 107          feeler_conn = self.nodes[0].add_outbound_p2p_connection(P2PFeelerReceiver(), p2p_idx=6, connection_type="feeler")
 108  
 109          # Feeler connection is closed
 110          assert not feeler_conn.is_connected
 111  
 112          # Verify version message received
 113          assert_equal(feeler_conn.message_count["version"], 1)
 114          # Feeler connections do not request tx relay
 115          assert_equal(feeler_conn.last_message["version"].relay, 0)
 116  
 117          self.log.info("Send version message early to node")
 118          # Normally the test framework would be shy and send the version message
 119          # only after it received one. See the on_version method. Check that
 120          # bitcoind behaves properly when a version is sent unexpectedly (but
 121          # tolerably) early.
 122          #
 123          # This checks that bitcoind sends its own version prior to processing
 124          # the remote version (and replying with a verack). Otherwise it would
 125          # be violating its own rules, such as "non-version message before
 126          # version handshake".
 127          ver_conn = self.nodes[0].add_outbound_p2p_connection(VersionSender(), p2p_idx=6, connection_type="outbound-full-relay", supports_v2_p2p=False, advertise_v2_p2p=False)
 128          ver_conn.sync_with_ping()
 129  
 130  
 131  if __name__ == '__main__':
 132      P2PAddConnections(__file__).main()
 133