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
):
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):
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)
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()
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
):
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)
92 def erase_three(self
):
93 os
.remove(self
.options
.tmpdir
+ "/node0/regtest/wallet.dat")
94 os
.remove(self
.options
.tmpdir
+ "/node1/regtest/wallet.dat")
95 os
.remove(self
.options
.tmpdir
+ "/node2/regtest/wallet.dat")
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.
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")
131 # Generate 101 more blocks, so any fees paid mature
132 self
.nodes
[3].generate(101)
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")
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/wallet.dat")
158 shutil
.copyfile(tmpdir
+ "/node1/wallet.bak", tmpdir
+ "/node1/regtest/wallet.dat")
159 shutil
.copyfile(tmpdir
+ "/node2/wallet.bak", tmpdir
+ "/node2/regtest/wallet.dat")
161 self
.log
.info("Re-starting nodes")
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")
173 #start node2 with no chain
174 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/blocks")
175 shutil
.rmtree(self
.options
.tmpdir
+ "/node2/regtest/chainstate")
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
)
194 if __name__
== '__main__':
195 WalletBackupTest().main()