p2p_compactblocks_hb.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2021-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 compact blocks HB selection logic."""
   6  
   7  from test_framework.test_framework import BitcoinTestFramework
   8  from test_framework.util import assert_equal
   9  
  10  
  11  class CompactBlocksConnectionTest(BitcoinTestFramework):
  12      """Test class for verifying selection of HB peer connections."""
  13  
  14      def set_test_params(self):
  15          self.setup_clean_chain = True
  16          self.num_nodes = 6
  17  
  18      def peer_info(self, from_node, to_node):
  19          """Query from_node for its getpeerinfo about to_node."""
  20          for peerinfo in self.nodes[from_node].getpeerinfo():
  21              if "(testnode%i)" % to_node in peerinfo['subver']:
  22                  return peerinfo
  23          return None
  24  
  25      def setup_network(self):
  26          self.setup_nodes()
  27          # Start network with everyone disconnected
  28          self.sync_all()
  29  
  30      def relay_block_through(self, peer):
  31          """Relay a new block through peer peer, and return HB status between 1 and [2,3,4,5]."""
  32          self.connect_nodes(peer, 0)
  33          self.generate(self.nodes[0], 1)
  34          self.disconnect_nodes(peer, 0)
  35  
  36          def status_to():
  37              return [self.peer_info(1, i)['bip152_hb_to'] for i in range(2, 6)]
  38  
  39          def status_from():
  40              return [self.peer_info(i, 1)['bip152_hb_from'] for i in range(2, 6)]
  41  
  42          self.wait_until(lambda: status_to() == status_from())
  43          return status_to()
  44  
  45      def run_test(self):
  46          self.log.info("Testing reserved high-bandwidth mode slot for outbound peer...")
  47  
  48          # Connect everyone to node 0, and mine some blocks to get all nodes out of IBD.
  49          for i in range(1, 6):
  50              self.connect_nodes(i, 0)
  51          self.generate(self.nodes[0], 2)
  52          for i in range(1, 6):
  53              self.disconnect_nodes(i, 0)
  54  
  55          # Construct network topology:
  56          # - Node 0 is the block producer
  57          # - Node 1 is the "target" node being tested
  58          # - Nodes 2-5 are intermediaries.
  59          #   - Node 1 has an outbound connection to node 2
  60          #   - Node 1 has inbound connections from nodes 3-5
  61          self.connect_nodes(3, 1)
  62          self.connect_nodes(4, 1)
  63          self.connect_nodes(5, 1)
  64          self.connect_nodes(1, 2)
  65  
  66          # Mine blocks subsequently relaying through nodes 3,4,5 (inbound to node 1)
  67          for nodeid in range(3, 6):
  68              status = self.relay_block_through(nodeid)
  69              assert_equal(status, [False, nodeid >= 3, nodeid >= 4, nodeid >= 5])
  70  
  71          # And again through each. This should not change HB status.
  72          for nodeid in range(3, 6):
  73              status = self.relay_block_through(nodeid)
  74              assert_equal(status, [False, True, True, True])
  75  
  76          # Now relay one block through peer 2 (outbound from node 1), so it should take HB status
  77          # from one of the inbounds.
  78          status = self.relay_block_through(2)
  79          assert_equal(status[0], True)
  80          assert_equal(sum(status), 3)
  81  
  82          # Now relay again through nodes 3,4,5. Since 2 is outbound, it should remain HB.
  83          for nodeid in range(3, 6):
  84              status = self.relay_block_through(nodeid)
  85              assert status[0]
  86              assert status[nodeid - 2]
  87              assert_equal(sum(status), 3)
  88  
  89          # Reconnect peer 2, and retry. Now the three inbounds should be HB again.
  90          self.disconnect_nodes(1, 2)
  91          self.connect_nodes(1, 2)
  92          for nodeid in range(3, 6):
  93              status = self.relay_block_through(nodeid)
  94              assert not status[0]
  95              assert status[nodeid - 2]
  96          assert_equal(status, [False, True, True, True])
  97  
  98  
  99  if __name__ == '__main__':
 100      CompactBlocksConnectionTest(__file__).main()
 101