You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

walletbackup.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #!/usr/bin/env python2
  2. # Copyright (c) 2014-2015 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. """
  6. Exercise the wallet backup code. Ported from walletbackup.sh.
  7. Test case is:
  8. 4 nodes. 1 2 and 3 send transactions between each other,
  9. fourth node is a miner.
  10. 1 2 3 each mine a block to start, then
  11. Miner creates 100 blocks so 1 2 3 each have 50 mature
  12. coins to spend.
  13. Then 5 iterations of 1/2/3 sending coins amongst
  14. themselves to get transactions in the wallets,
  15. and the miner mining one block.
  16. Wallets are backed up using dumpwallet/backupwallet.
  17. Then 5 more iterations of transactions and mining a block.
  18. Miner then generates 101 more blocks, so any
  19. transaction fees paid mature.
  20. Sanity check:
  21. Sum(1,2,3,4 balances) == 114*50
  22. 1/2/3 are shutdown, and their wallets erased.
  23. Then restore using wallet.dat backup. And
  24. confirm 1/2/3/4 balances are same as before.
  25. Shutdown again, restore using importwallet,
  26. and confirm again balances are correct.
  27. """
  28. from test_framework.test_framework import BitcoinTestFramework
  29. from test_framework.util import *
  30. from random import randint
  31. import logging
  32. logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
  33. class WalletBackupTest(BitcoinTestFramework):
  34. def setup_chain(self):
  35. logging.info("Initializing test directory "+self.options.tmpdir)
  36. initialize_chain_clean(self.options.tmpdir, 4)
  37. # This mirrors how the network was setup in the bash test
  38. def setup_network(self, split=False):
  39. # nodes 1, 2,3 are spenders, let's give them a keypool=100
  40. extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
  41. self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
  42. connect_nodes(self.nodes[0], 3)
  43. connect_nodes(self.nodes[1], 3)
  44. connect_nodes(self.nodes[2], 3)
  45. connect_nodes(self.nodes[2], 0)
  46. self.is_network_split=False
  47. self.sync_all()
  48. def one_send(self, from_node, to_address):
  49. if (randint(1,2) == 1):
  50. amount = Decimal(randint(1,10)) / Decimal(10)
  51. self.nodes[from_node].sendtoaddress(to_address, amount)
  52. def do_one_round(self):
  53. a0 = self.nodes[0].getnewaddress()
  54. a1 = self.nodes[1].getnewaddress()
  55. a2 = self.nodes[2].getnewaddress()
  56. self.one_send(0, a1)
  57. self.one_send(0, a2)
  58. self.one_send(1, a0)
  59. self.one_send(1, a2)
  60. self.one_send(2, a0)
  61. self.one_send(2, a1)
  62. # Have the miner (node3) mine a block.
  63. # Must sync mempools before mining.
  64. sync_mempools(self.nodes)
  65. self.nodes[3].generate(1)
  66. # As above, this mirrors the original bash test.
  67. def start_three(self):
  68. self.nodes[0] = start_node(0, self.options.tmpdir)
  69. self.nodes[1] = start_node(1, self.options.tmpdir)
  70. self.nodes[2] = start_node(2, self.options.tmpdir)
  71. connect_nodes(self.nodes[0], 3)
  72. connect_nodes(self.nodes[1], 3)
  73. connect_nodes(self.nodes[2], 3)
  74. connect_nodes(self.nodes[2], 0)
  75. def stop_three(self):
  76. stop_node(self.nodes[0], 0)
  77. stop_node(self.nodes[1], 1)
  78. stop_node(self.nodes[2], 2)
  79. def erase_three(self):
  80. os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
  81. os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
  82. os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat")
  83. def run_test(self):
  84. logging.info("Generating initial blockchain")
  85. self.nodes[0].generate(1)
  86. sync_blocks(self.nodes)
  87. self.nodes[1].generate(1)
  88. sync_blocks(self.nodes)
  89. self.nodes[2].generate(1)
  90. sync_blocks(self.nodes)
  91. self.nodes[3].generate(100)
  92. sync_blocks(self.nodes)
  93. assert_equal(self.nodes[0].getbalance(), 50)
  94. assert_equal(self.nodes[1].getbalance(), 50)
  95. assert_equal(self.nodes[2].getbalance(), 50)
  96. assert_equal(self.nodes[3].getbalance(), 0)
  97. logging.info("Creating transactions")
  98. # Five rounds of sending each other transactions.
  99. for i in range(5):
  100. self.do_one_round()
  101. logging.info("Backing up")
  102. tmpdir = self.options.tmpdir
  103. self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
  104. self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
  105. self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
  106. self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
  107. self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
  108. self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
  109. logging.info("More transactions")
  110. for i in range(5):
  111. self.do_one_round()
  112. # Generate 101 more blocks, so any fees paid mature
  113. self.nodes[3].generate(101)
  114. self.sync_all()
  115. balance0 = self.nodes[0].getbalance()
  116. balance1 = self.nodes[1].getbalance()
  117. balance2 = self.nodes[2].getbalance()
  118. balance3 = self.nodes[3].getbalance()
  119. total = balance0 + balance1 + balance2 + balance3
  120. # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
  121. # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700.
  122. assert_equal(total, 5700)
  123. ##
  124. # Test restoring spender wallets from backups
  125. ##
  126. logging.info("Restoring using wallet.dat")
  127. self.stop_three()
  128. self.erase_three()
  129. # Start node2 with no chain
  130. shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
  131. shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
  132. # Restore wallets from backup
  133. shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat")
  134. shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
  135. shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
  136. logging.info("Re-starting nodes")
  137. self.start_three()
  138. sync_blocks(self.nodes)
  139. assert_equal(self.nodes[0].getbalance(), balance0)
  140. assert_equal(self.nodes[1].getbalance(), balance1)
  141. assert_equal(self.nodes[2].getbalance(), balance2)
  142. logging.info("Restoring using dumped wallet")
  143. self.stop_three()
  144. self.erase_three()
  145. #start node2 with no chain
  146. shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
  147. shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
  148. self.start_three()
  149. assert_equal(self.nodes[0].getbalance(), 0)
  150. assert_equal(self.nodes[1].getbalance(), 0)
  151. assert_equal(self.nodes[2].getbalance(), 0)
  152. self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
  153. self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
  154. self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
  155. sync_blocks(self.nodes)
  156. assert_equal(self.nodes[0].getbalance(), balance0)
  157. assert_equal(self.nodes[1].getbalance(), balance1)
  158. assert_equal(self.nodes[2].getbalance(), balance2)
  159. if __name__ == '__main__':
  160. WalletBackupTest().main()