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.
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
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.
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.
33 from random
import randint
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
.setup_clean_chain
= True
42 # nodes 1, 2,3 are spenders, let's give them a keypool=100
43 self
.extra_args
= [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
45 def setup_network(self
, split
=False):
47 connect_nodes(self
.nodes
[0], 3)
48 connect_nodes(self
.nodes
[1], 3)
49 connect_nodes(self
.nodes
[2], 3)
50 connect_nodes(self
.nodes
[2], 0)
53 def one_send(self
, from_node
, to_address
):
54 if (randint(1,2) == 1):
55 amount
= Decimal(randint(1,10)) / Decimal(10)
56 self
.nodes
[from_node
].sendtoaddress(to_address
, amount
)
58 def do_one_round(self
):
59 a0
= self
.nodes
[0].getnewaddress()
60 a1
= self
.nodes
[1].getnewaddress()
61 a2
= self
.nodes
[2].getnewaddress()
70 # Have the miner (node3) mine a block.
71 # Must sync mempools before mining.
72 sync_mempools(self
.nodes
)
73 self
.nodes
[3].generate(1)
74 sync_blocks(self
.nodes
)
76 # As above, this mirrors the original bash test.
77 def start_three(self
):
81 connect_nodes(self
.nodes
[0], 3)
82 connect_nodes(self
.nodes
[1], 3)
83 connect_nodes(self
.nodes
[2], 3)
84 connect_nodes(self
.nodes
[2], 0)
91 def erase_three(self
):
92 os
.remove(self
.options
.tmpdir
+ "/node0/regtest/wallet.dat")
93 os
.remove(self
.options
.tmpdir
+ "/node1/regtest/wallet.dat")
94 os
.remove(self
.options
.tmpdir
+ "/node2/regtest/wallet.dat")
97 self
.log
.info("Generating initial blockchain")
98 self
.nodes
[0].generate(1)
99 sync_blocks(self
.nodes
)
100 self
.nodes
[1].generate(1)
101 sync_blocks(self
.nodes
)
102 self
.nodes
[2].generate(1)
103 sync_blocks(self
.nodes
)
104 self
.nodes
[3].generate(100)
105 sync_blocks(self
.nodes
)
107 assert_equal(self
.nodes
[0].getbalance(), 50)
108 assert_equal(self
.nodes
[1].getbalance(), 50)
109 assert_equal(self
.nodes
[2].getbalance(), 50)
110 assert_equal(self
.nodes
[3].getbalance(), 0)
112 self
.log
.info("Creating transactions")
113 # Five rounds of sending each other transactions.
117 self
.log
.info("Backing up")
118 tmpdir
= self
.options
.tmpdir
119 self
.nodes
[0].backupwallet(tmpdir
+ "/node0/wallet.bak")
120 self
.nodes
[0].dumpwallet(tmpdir
+ "/node0/wallet.dump")
121 self
.nodes
[1].backupwallet(tmpdir
+ "/node1/wallet.bak")
122 self
.nodes
[1].dumpwallet(tmpdir
+ "/node1/wallet.dump")
123 self
.nodes
[2].backupwallet(tmpdir
+ "/node2/wallet.bak")
124 self
.nodes
[2].dumpwallet(tmpdir
+ "/node2/wallet.dump")
126 self
.log
.info("More transactions")
130 # Generate 101 more blocks, so any fees paid mature
131 self
.nodes
[3].generate(101)
134 balance0
= self
.nodes
[0].getbalance()
135 balance1
= self
.nodes
[1].getbalance()
136 balance2
= self
.nodes
[2].getbalance()
137 balance3
= self
.nodes
[3].getbalance()
138 total
= balance0
+ balance1
+ balance2
+ balance3
140 # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
141 # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700.
142 assert_equal(total
, 5700)
145 # Test restoring spender wallets from backups
147 self
.log
.info("Restoring using wallet.dat")
151 # Start node2 with no chain
152 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/blocks")
153 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/chainstate")
155 # Restore wallets from backup
156 shutil
.copyfile(tmpdir
+ "/node0/wallet.bak", tmpdir
+ "/node0/regtest/wallet.dat")
157 shutil
.copyfile(tmpdir
+ "/node1/wallet.bak", tmpdir
+ "/node1/regtest/wallet.dat")
158 shutil
.copyfile(tmpdir
+ "/node2/wallet.bak", tmpdir
+ "/node2/regtest/wallet.dat")
160 self
.log
.info("Re-starting nodes")
162 sync_blocks(self
.nodes
)
164 assert_equal(self
.nodes
[0].getbalance(), balance0
)
165 assert_equal(self
.nodes
[1].getbalance(), balance1
)
166 assert_equal(self
.nodes
[2].getbalance(), balance2
)
168 self
.log
.info("Restoring using dumped wallet")
172 #start node2 with no chain
173 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/blocks")
174 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/chainstate")
178 assert_equal(self
.nodes
[0].getbalance(), 0)
179 assert_equal(self
.nodes
[1].getbalance(), 0)
180 assert_equal(self
.nodes
[2].getbalance(), 0)
182 self
.nodes
[0].importwallet(tmpdir
+ "/node0/wallet.dump")
183 self
.nodes
[1].importwallet(tmpdir
+ "/node1/wallet.dump")
184 self
.nodes
[2].importwallet(tmpdir
+ "/node2/wallet.dump")
186 sync_blocks(self
.nodes
)
188 assert_equal(self
.nodes
[0].getbalance(), balance0
)
189 assert_equal(self
.nodes
[1].getbalance(), balance1
)
190 assert_equal(self
.nodes
[2].getbalance(), balance2
)
193 if __name__
== '__main__':
194 WalletBackupTest().main()