rpc_preciousblock.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2015-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 the preciousblock RPC."""
   6  
   7  from test_framework.test_framework import BitcoinTestFramework
   8  from test_framework.util import (
   9      assert_not_equal,
  10      assert_equal,
  11  )
  12  
  13  def unidirectional_node_sync_via_rpc(node_src, node_dest):
  14      blocks_to_copy = []
  15      blockhash = node_src.getbestblockhash()
  16      while True:
  17          try:
  18              assert len(node_dest.getblock(blockhash, False)) > 0
  19              break
  20          except Exception:
  21              blocks_to_copy.append(blockhash)
  22              blockhash = node_src.getblockheader(blockhash, True)['previousblockhash']
  23      blocks_to_copy.reverse()
  24      for blockhash in blocks_to_copy:
  25          blockdata = node_src.getblock(blockhash, False)
  26          assert node_dest.submitblock(blockdata) in (None, 'inconclusive')
  27  
  28  def node_sync_via_rpc(nodes):
  29      for node_src in nodes:
  30          for node_dest in nodes:
  31              if node_src is node_dest:
  32                  continue
  33              unidirectional_node_sync_via_rpc(node_src, node_dest)
  34  
  35  class PreciousTest(BitcoinTestFramework):
  36      def set_test_params(self):
  37          self.setup_clean_chain = True
  38          self.num_nodes = 3
  39  
  40      def setup_network(self):
  41          self.setup_nodes()
  42  
  43      def run_test(self):
  44          self.log.info("Ensure submitblock can in principle reorg to a competing chain")
  45          self.generate(self.nodes[0], 1, sync_fun=self.no_op)
  46          assert_equal(self.nodes[0].getblockcount(), 1)
  47          hashZ = self.generate(self.nodes[1], 2, sync_fun=self.no_op)[-1]
  48          assert_equal(self.nodes[1].getblockcount(), 2)
  49          node_sync_via_rpc(self.nodes[0:3])
  50          assert_equal(self.nodes[0].getbestblockhash(), hashZ)
  51  
  52          self.log.info("Mine blocks A-B-C on Node 0")
  53          hashC = self.generate(self.nodes[0], 3, sync_fun=self.no_op)[-1]
  54          assert_equal(self.nodes[0].getblockcount(), 5)
  55          self.log.info("Mine competing blocks E-F-G on Node 1")
  56          hashG = self.generate(self.nodes[1], 3, sync_fun=self.no_op)[-1]
  57          assert_equal(self.nodes[1].getblockcount(), 5)
  58          assert_not_equal(hashC, hashG)
  59          self.log.info("Connect nodes and check no reorg occurs")
  60          # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
  61          node_sync_via_rpc(self.nodes[0:2])
  62          self.connect_nodes(0, 1)
  63          assert_equal(self.nodes[0].getbestblockhash(), hashC)
  64          assert_equal(self.nodes[1].getbestblockhash(), hashG)
  65          self.log.info("Make Node0 prefer block G")
  66          self.nodes[0].preciousblock(hashG)
  67          assert_equal(self.nodes[0].getbestblockhash(), hashG)
  68          self.log.info("Make Node0 prefer block C again")
  69          self.nodes[0].preciousblock(hashC)
  70          assert_equal(self.nodes[0].getbestblockhash(), hashC)
  71          self.log.info("Make Node1 prefer block C")
  72          self.nodes[1].preciousblock(hashC)
  73          self.sync_blocks(self.nodes[0:2])  # wait because node 1 may not have downloaded hashC
  74          assert_equal(self.nodes[1].getbestblockhash(), hashC)
  75          self.log.info("Make Node1 prefer block G again")
  76          self.nodes[1].preciousblock(hashG)
  77          assert_equal(self.nodes[1].getbestblockhash(), hashG)
  78          self.log.info("Make Node0 prefer block G again")
  79          self.nodes[0].preciousblock(hashG)
  80          assert_equal(self.nodes[0].getbestblockhash(), hashG)
  81          self.log.info("Make Node1 prefer block C again")
  82          self.nodes[1].preciousblock(hashC)
  83          assert_equal(self.nodes[1].getbestblockhash(), hashC)
  84          self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
  85          self.generate(self.nodes[0], 1, sync_fun=self.no_op)
  86          assert_equal(self.nodes[0].getblockcount(), 6)
  87          self.sync_blocks(self.nodes[0:2])
  88          hashH = self.nodes[0].getbestblockhash()
  89          assert_equal(self.nodes[1].getbestblockhash(), hashH)
  90          self.log.info("Node1 should not be able to prefer block C anymore")
  91          self.nodes[1].preciousblock(hashC)
  92          assert_equal(self.nodes[1].getbestblockhash(), hashH)
  93          self.log.info("Mine competing blocks I-J-K-L on Node 2")
  94          self.generate(self.nodes[2], 4, sync_fun=self.no_op)
  95          assert_equal(self.nodes[2].getblockcount(), 6)
  96          hashL = self.nodes[2].getbestblockhash()
  97          self.log.info("Connect nodes and check no reorg occurs")
  98          node_sync_via_rpc(self.nodes[1:3])
  99          self.connect_nodes(1, 2)
 100          self.connect_nodes(0, 2)
 101          assert_equal(self.nodes[0].getbestblockhash(), hashH)
 102          assert_equal(self.nodes[1].getbestblockhash(), hashH)
 103          assert_equal(self.nodes[2].getbestblockhash(), hashL)
 104          self.log.info("Make Node1 prefer block L")
 105          self.nodes[1].preciousblock(hashL)
 106          assert_equal(self.nodes[1].getbestblockhash(), hashL)
 107          self.log.info("Make Node2 prefer block H")
 108          self.nodes[2].preciousblock(hashH)
 109          assert_equal(self.nodes[2].getbestblockhash(), hashH)
 110  
 111  if __name__ == '__main__':
 112      PreciousTest(__file__).main()
 113