Merge #11743: qa: Add multiwallet prefix test
[bitcoinplatinum.git] / test / functional / walletbackup.py
blob8ef5620cd8cfc6158d1b6ccf1602adce1f288de0
1 #!/usr/bin/env python3
2 # Copyright (c) 2014-2016 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 wallet backup features.
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.
17 Wallets are backed up using dumpwallet/backupwallet.
18 Then 5 more iterations of transactions and mining a block.
20 Miner then generates 101 more blocks, so any
21 transaction fees paid mature.
23 Sanity check:
24 Sum(1,2,3,4 balances) == 114*50
26 1/2/3 are shutdown, and their wallets erased.
27 Then restore using wallet.dat backup. And
28 confirm 1/2/3/4 balances are same as before.
30 Shutdown again, restore using importwallet,
31 and confirm again balances are correct.
32 """
33 from random import randint
34 import shutil
36 from test_framework.test_framework import BitcoinTestFramework
37 from test_framework.util import *
39 class WalletBackupTest(BitcoinTestFramework):
40 def set_test_params(self):
41 self.num_nodes = 4
42 self.setup_clean_chain = True
43 # nodes 1, 2,3 are spenders, let's give them a keypool=100
44 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
46 def setup_network(self, split=False):
47 self.setup_nodes()
48 connect_nodes(self.nodes[0], 3)
49 connect_nodes(self.nodes[1], 3)
50 connect_nodes(self.nodes[2], 3)
51 connect_nodes(self.nodes[2], 0)
52 self.sync_all()
54 def one_send(self, from_node, to_address):
55 if (randint(1,2) == 1):
56 amount = Decimal(randint(1,10)) / Decimal(10)
57 self.nodes[from_node].sendtoaddress(to_address, amount)
59 def do_one_round(self):
60 a0 = self.nodes[0].getnewaddress()
61 a1 = self.nodes[1].getnewaddress()
62 a2 = self.nodes[2].getnewaddress()
64 self.one_send(0, a1)
65 self.one_send(0, a2)
66 self.one_send(1, a0)
67 self.one_send(1, a2)
68 self.one_send(2, a0)
69 self.one_send(2, a1)
71 # Have the miner (node3) mine a block.
72 # Must sync mempools before mining.
73 sync_mempools(self.nodes)
74 self.nodes[3].generate(1)
75 sync_blocks(self.nodes)
77 # As above, this mirrors the original bash test.
78 def start_three(self):
79 self.start_node(0)
80 self.start_node(1)
81 self.start_node(2)
82 connect_nodes(self.nodes[0], 3)
83 connect_nodes(self.nodes[1], 3)
84 connect_nodes(self.nodes[2], 3)
85 connect_nodes(self.nodes[2], 0)
87 def stop_three(self):
88 self.stop_node(0)
89 self.stop_node(1)
90 self.stop_node(2)
92 def erase_three(self):
93 os.remove(self.options.tmpdir + "/node0/regtest/wallets/wallet.dat")
94 os.remove(self.options.tmpdir + "/node1/regtest/wallets/wallet.dat")
95 os.remove(self.options.tmpdir + "/node2/regtest/wallets/wallet.dat")
97 def run_test(self):
98 self.log.info("Generating initial blockchain")
99 self.nodes[0].generate(1)
100 sync_blocks(self.nodes)
101 self.nodes[1].generate(1)
102 sync_blocks(self.nodes)
103 self.nodes[2].generate(1)
104 sync_blocks(self.nodes)
105 self.nodes[3].generate(100)
106 sync_blocks(self.nodes)
108 assert_equal(self.nodes[0].getbalance(), 50)
109 assert_equal(self.nodes[1].getbalance(), 50)
110 assert_equal(self.nodes[2].getbalance(), 50)
111 assert_equal(self.nodes[3].getbalance(), 0)
113 self.log.info("Creating transactions")
114 # Five rounds of sending each other transactions.
115 for i in range(5):
116 self.do_one_round()
118 self.log.info("Backing up")
119 tmpdir = self.options.tmpdir
120 self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
121 self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
122 self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
123 self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
124 self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
125 self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
127 self.log.info("More transactions")
128 for i in range(5):
129 self.do_one_round()
131 # Generate 101 more blocks, so any fees paid mature
132 self.nodes[3].generate(101)
133 self.sync_all()
135 balance0 = self.nodes[0].getbalance()
136 balance1 = self.nodes[1].getbalance()
137 balance2 = self.nodes[2].getbalance()
138 balance3 = self.nodes[3].getbalance()
139 total = balance0 + balance1 + balance2 + balance3
141 # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
142 # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700.
143 assert_equal(total, 5700)
146 # Test restoring spender wallets from backups
148 self.log.info("Restoring using wallet.dat")
149 self.stop_three()
150 self.erase_three()
152 # Start node2 with no chain
153 shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
154 shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
156 # Restore wallets from backup
157 shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallets/wallet.dat")
158 shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallets/wallet.dat")
159 shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallets/wallet.dat")
161 self.log.info("Re-starting nodes")
162 self.start_three()
163 sync_blocks(self.nodes)
165 assert_equal(self.nodes[0].getbalance(), balance0)
166 assert_equal(self.nodes[1].getbalance(), balance1)
167 assert_equal(self.nodes[2].getbalance(), balance2)
169 self.log.info("Restoring using dumped wallet")
170 self.stop_three()
171 self.erase_three()
173 #start node2 with no chain
174 shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
175 shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
177 self.start_three()
179 assert_equal(self.nodes[0].getbalance(), 0)
180 assert_equal(self.nodes[1].getbalance(), 0)
181 assert_equal(self.nodes[2].getbalance(), 0)
183 self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
184 self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
185 self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
187 sync_blocks(self.nodes)
189 assert_equal(self.nodes[0].getbalance(), balance0)
190 assert_equal(self.nodes[1].getbalance(), balance1)
191 assert_equal(self.nodes[2].getbalance(), balance2)
193 # Backup to source wallet file must fail
194 sourcePaths = [
195 tmpdir + "/node0/regtest/wallets/wallet.dat",
196 tmpdir + "/node0/./regtest/wallets/wallet.dat",
197 tmpdir + "/node0/regtest/wallets/",
198 tmpdir + "/node0/regtest/wallets"]
200 for sourcePath in sourcePaths:
201 assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath)
204 if __name__ == '__main__':
205 WalletBackupTest().main()