Dash Core  0.12.2.1
P2P Digital Currency
walletbackup.py
Go to the documentation of this file.
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 """
7 Exercise the wallet backup code. Ported from walletbackup.sh.
8 
9 Test case is:
10 4 nodes. 1 2 and 3 send transactions between each other,
11 fourth node is a miner.
12 1 2 3 each mine a block to start, then
13 Miner creates 100 blocks so 1 2 3 each have 500 mature
14 coins to spend.
15 Then 5 iterations of 1/2/3 sending coins amongst
16 themselves to get transactions in the wallets,
17 and the miner mining one block.
18 
19 Wallets are backed up using dumpwallet/backupwallet.
20 Then 5 more iterations of transactions and mining a block.
21 
22 Miner then generates 101 more blocks, so any
23 transaction fees paid mature.
24 
25 Sanity check:
26  Sum(1,2,3,4 balances) == 114*500
27 
28 1/2/3 are shutdown, and their wallets erased.
29 Then restore using wallet.dat backup. And
30 confirm 1/2/3/4 balances are same as before.
31 
32 Shutdown again, restore using importwallet,
33 and confirm again balances are correct.
34 """
35 
36 from test_framework.test_framework import BitcoinTestFramework
37 from test_framework.util import *
38 from random import randint
39 import logging
40 logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
41 
43 
44  def setup_chain(self):
45  logging.info("Initializing test directory "+self.options.tmpdir)
46  initialize_chain_clean(self.options.tmpdir, 4)
47 
48  # This mirrors how the network was setup in the bash test
49  def setup_network(self, split=False):
50  # nodes 1, 2,3 are spenders, let's give them a keypool=100
51  extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
52  self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
53  connect_nodes(self.nodes[0], 3)
54  connect_nodes(self.nodes[1], 3)
55  connect_nodes(self.nodes[2], 3)
56  connect_nodes(self.nodes[2], 0)
57  self.is_network_split=False
58  self.sync_all()
59 
60  def one_send(self, from_node, to_address):
61  if (randint(1,2) == 1):
62  amount = Decimal(randint(1,10)) / Decimal(10)
63  self.nodes[from_node].sendtoaddress(to_address, amount)
64 
65  def do_one_round(self):
66  a0 = self.nodes[0].getnewaddress()
67  a1 = self.nodes[1].getnewaddress()
68  a2 = self.nodes[2].getnewaddress()
69 
70  self.one_send(0, a1)
71  self.one_send(0, a2)
72  self.one_send(1, a0)
73  self.one_send(1, a2)
74  self.one_send(2, a0)
75  self.one_send(2, a1)
76 
77  # Have the miner (node3) mine a block.
78  # Must sync mempools before mining.
79  sync_mempools(self.nodes)
80  self.nodes[3].generate(1)
81 
82  # As above, this mirrors the original bash test.
83  def start_three(self):
84  self.nodes[0] = start_node(0, self.options.tmpdir)
85  self.nodes[1] = start_node(1, self.options.tmpdir)
86  self.nodes[2] = start_node(2, self.options.tmpdir)
87  connect_nodes(self.nodes[0], 3)
88  connect_nodes(self.nodes[1], 3)
89  connect_nodes(self.nodes[2], 3)
90  connect_nodes(self.nodes[2], 0)
91 
92  def stop_three(self):
93  stop_node(self.nodes[0], 0)
94  stop_node(self.nodes[1], 1)
95  stop_node(self.nodes[2], 2)
96 
97  def erase_three(self):
98  os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat")
99  os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
100  os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat")
101 
102  def run_test(self):
103  logging.info("Generating initial blockchain")
104  self.nodes[0].generate(1)
105  sync_blocks(self.nodes)
106  self.nodes[1].generate(1)
107  sync_blocks(self.nodes)
108  self.nodes[2].generate(1)
109  sync_blocks(self.nodes)
110  self.nodes[3].generate(100)
111  sync_blocks(self.nodes)
112 
113  assert_equal(self.nodes[0].getbalance(), 500)
114  assert_equal(self.nodes[1].getbalance(), 500)
115  assert_equal(self.nodes[2].getbalance(), 500)
116  assert_equal(self.nodes[3].getbalance(), 0)
117 
118  logging.info("Creating transactions")
119  # Five rounds of sending each other transactions.
120  for i in range(5):
121  self.do_one_round()
122 
123  logging.info("Backing up")
124  tmpdir = self.options.tmpdir
125  self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
126  self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
127  self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
128  self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
129  self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
130  self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
131 
132  logging.info("More transactions")
133  for i in range(5):
134  self.do_one_round()
135 
136  # Generate 101 more blocks, so any fees paid mature
137  self.nodes[3].generate(101)
138  self.sync_all()
139 
140  balance0 = self.nodes[0].getbalance()
141  balance1 = self.nodes[1].getbalance()
142  balance2 = self.nodes[2].getbalance()
143  balance3 = self.nodes[3].getbalance()
144  total = balance0 + balance1 + balance2 + balance3
145 
146  # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
147  # 114 are mature, so the sum of all wallets should be 114 * 500 = 57000.
148  assert_equal(total, 57000)
149 
150 
153  logging.info("Restoring using wallet.dat")
154  self.stop_three()
155  self.erase_three()
156 
157  # Start node2 with no chain
158  shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
159  shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
160 
161  # Restore wallets from backup
162  shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat")
163  shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
164  shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
165 
166  logging.info("Re-starting nodes")
167  self.start_three()
168  sync_blocks(self.nodes)
169 
170  assert_equal(self.nodes[0].getbalance(), balance0)
171  assert_equal(self.nodes[1].getbalance(), balance1)
172  assert_equal(self.nodes[2].getbalance(), balance2)
173 
174  logging.info("Restoring using dumped wallet")
175  self.stop_three()
176  self.erase_three()
177 
178  #start node2 with no chain
179  shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
180  shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
181 
182  self.start_three()
183 
184  assert_equal(self.nodes[0].getbalance(), 0)
185  assert_equal(self.nodes[1].getbalance(), 0)
186  assert_equal(self.nodes[2].getbalance(), 0)
187 
188  self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
189  self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
190  self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
191 
192  sync_blocks(self.nodes)
193 
194  assert_equal(self.nodes[0].getbalance(), balance0)
195  assert_equal(self.nodes[1].getbalance(), balance1)
196  assert_equal(self.nodes[2].getbalance(), balance2)
197 
198 
199 if __name__ == '__main__':
UniValue dumpwallet(const UniValue &params, bool fHelp)
Definition: rpcdump.cpp:629
def setup_network(self, split=False)
Definition: walletbackup.py:49
UniValue getbalance(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:792
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None)
Definition: util.py:305
UniValue backupwallet(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:1937
UniValue sendtoaddress(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:409
def connect_nodes(from_connection, node_num)
Definition: util.py:343
UniValue getnewaddress(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:113
def sync_mempools(rpc_connections, wait=1)
Definition: util.py:127
def initialize_chain_clean(test_dir, num_nodes)
Definition: util.py:252
def one_send(self, from_node, to_address)
Definition: walletbackup.py:60
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None)
Definition: util.py:281
def stop_node(node, i)
Definition: util.py:323
UniValue importwallet(const UniValue &params, bool fHelp)
Definition: rpcdump.cpp:305
UniValue generate(const UniValue &params, bool fHelp)
Definition: mining.cpp:122
def sync_blocks(rpc_connections, wait=1)
Definition: util.py:117
def run_test(self)
Test restoring spender wallets from backups.
def assert_equal(thing1, thing2)
Definition: util.py:461