aboutsummaryrefslogtreecommitdiff
path: root/test/functional/wallet_backup.py
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2018-01-24 20:42:46 -0500
committerMarcoFalke <falke.marco@gmail.com>2018-01-24 20:43:13 -0500
commit6970b30c6f1d2be7947295fe18f2390649b17a4b (patch)
tree6d8c8226f05a765483eff94aedfccd8cf483cf55 /test/functional/wallet_backup.py
parentf359afcc410432ed5d30001acda0c66741ee8935 (diff)
parent6f881cc8809e2c0d0150c47494bc37f2eb05ec66 (diff)
Merge #11774: [tests] Rename functional tests
6f881cc880 [tests] Remove EXPECTED_VIOLATION_COUNT (Anthony Towns) 3150b3fea7 [tests] Rename misc functional tests. (Anthony Towns) 81b79f2c39 [tests] Rename rpc_* functional tests. (Anthony Towns) 61b8f7f273 [tests] Rename p2p_* functional tests. (Anthony Towns) 90600bc7db [tests] Rename wallet_* functional tests. (Anthony Towns) ca6523d0c8 [tests] Rename feature_* functional tests. (Anthony Towns) Pull request description: This PR changes the functional tests to have a consistent naming scheme: tests for individual RPC methods are named rpc_... tests for interfaces (REST, ZMQ, RPC features) are named interface_... tests that explicitly test the p2p interface are named p2p_... tests for wallet features are named wallet_... tests for mining features are named mining_... tests for mempool behaviour are named mempool_... tests for full features that aren't wallet/mining/mempool are named feature_... Rationale: it's sometimes difficult for new contributors to know what's already covered by existing tests and where new tests should be added. Naming in a consistent fashion makes it easier to see what's already covered at a glance. Tree-SHA512: 4246790552d42bbd95f6d5bdf67702b81b3b2c583ce7eaf1fe6d8e254721279b47315973c6e9ae82dad6e4c747f12188160764bf2624c0f8f3b4d39330ec8b16
Diffstat (limited to 'test/functional/wallet_backup.py')
-rwxr-xr-xtest/functional/wallet_backup.py205
1 files changed, 205 insertions, 0 deletions
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
new file mode 100755
index 0000000000..b4be7debb5
--- /dev/null
+++ b/test/functional/wallet_backup.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test the wallet backup features.
+
+Test case is:
+4 nodes. 1 2 and 3 send transactions between each other,
+fourth node is a miner.
+1 2 3 each mine a block to start, then
+Miner creates 100 blocks so 1 2 3 each have 50 mature
+coins to spend.
+Then 5 iterations of 1/2/3 sending coins amongst
+themselves to get transactions in the wallets,
+and the miner mining one block.
+
+Wallets are backed up using dumpwallet/backupwallet.
+Then 5 more iterations of transactions and mining a block.
+
+Miner then generates 101 more blocks, so any
+transaction fees paid mature.
+
+Sanity check:
+ Sum(1,2,3,4 balances) == 114*50
+
+1/2/3 are shutdown, and their wallets erased.
+Then restore using wallet.dat backup. And
+confirm 1/2/3/4 balances are same as before.
+
+Shutdown again, restore using importwallet,
+and confirm again balances are correct.
+"""
+from random import randint
+import shutil
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class WalletBackupTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 4
+ self.setup_clean_chain = True
+ # nodes 1, 2,3 are spenders, let's give them a keypool=100
+ self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
+
+ def setup_network(self, split=False):
+ self.setup_nodes()
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[1], 3)
+ connect_nodes(self.nodes[2], 3)
+ connect_nodes(self.nodes[2], 0)
+ self.sync_all()
+
+ def one_send(self, from_node, to_address):
+ if (randint(1,2) == 1):
+ amount = Decimal(randint(1,10)) / Decimal(10)
+ self.nodes[from_node].sendtoaddress(to_address, amount)
+
+ def do_one_round(self):
+ a0 = self.nodes[0].getnewaddress()
+ a1 = self.nodes[1].getnewaddress()
+ a2 = self.nodes[2].getnewaddress()
+
+ self.one_send(0, a1)
+ self.one_send(0, a2)
+ self.one_send(1, a0)
+ self.one_send(1, a2)
+ self.one_send(2, a0)
+ self.one_send(2, a1)
+
+ # Have the miner (node3) mine a block.
+ # Must sync mempools before mining.
+ sync_mempools(self.nodes)
+ self.nodes[3].generate(1)
+ sync_blocks(self.nodes)
+
+ # As above, this mirrors the original bash test.
+ def start_three(self):
+ self.start_node(0)
+ self.start_node(1)
+ self.start_node(2)
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[1], 3)
+ connect_nodes(self.nodes[2], 3)
+ connect_nodes(self.nodes[2], 0)
+
+ def stop_three(self):
+ self.stop_node(0)
+ self.stop_node(1)
+ self.stop_node(2)
+
+ def erase_three(self):
+ os.remove(self.options.tmpdir + "/node0/regtest/wallets/wallet.dat")
+ os.remove(self.options.tmpdir + "/node1/regtest/wallets/wallet.dat")
+ os.remove(self.options.tmpdir + "/node2/regtest/wallets/wallet.dat")
+
+ def run_test(self):
+ self.log.info("Generating initial blockchain")
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+ self.nodes[1].generate(1)
+ sync_blocks(self.nodes)
+ self.nodes[2].generate(1)
+ sync_blocks(self.nodes)
+ self.nodes[3].generate(100)
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), 50)
+ assert_equal(self.nodes[1].getbalance(), 50)
+ assert_equal(self.nodes[2].getbalance(), 50)
+ assert_equal(self.nodes[3].getbalance(), 0)
+
+ self.log.info("Creating transactions")
+ # Five rounds of sending each other transactions.
+ for i in range(5):
+ self.do_one_round()
+
+ self.log.info("Backing up")
+ tmpdir = self.options.tmpdir
+ self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
+ self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
+ self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
+ self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
+ self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
+ self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
+
+ self.log.info("More transactions")
+ for i in range(5):
+ self.do_one_round()
+
+ # Generate 101 more blocks, so any fees paid mature
+ self.nodes[3].generate(101)
+ self.sync_all()
+
+ balance0 = self.nodes[0].getbalance()
+ balance1 = self.nodes[1].getbalance()
+ balance2 = self.nodes[2].getbalance()
+ balance3 = self.nodes[3].getbalance()
+ total = balance0 + balance1 + balance2 + balance3
+
+ # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.)
+ # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700.
+ assert_equal(total, 5700)
+
+ ##
+ # Test restoring spender wallets from backups
+ ##
+ self.log.info("Restoring using wallet.dat")
+ self.stop_three()
+ self.erase_three()
+
+ # Start node2 with no chain
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
+
+ # Restore wallets from backup
+ shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallets/wallet.dat")
+ shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallets/wallet.dat")
+ shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallets/wallet.dat")
+
+ self.log.info("Re-starting nodes")
+ self.start_three()
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), balance0)
+ assert_equal(self.nodes[1].getbalance(), balance1)
+ assert_equal(self.nodes[2].getbalance(), balance2)
+
+ self.log.info("Restoring using dumped wallet")
+ self.stop_three()
+ self.erase_three()
+
+ #start node2 with no chain
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks")
+ shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
+
+ self.start_three()
+
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ assert_equal(self.nodes[2].getbalance(), 0)
+
+ self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
+ self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
+ self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
+
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getbalance(), balance0)
+ assert_equal(self.nodes[1].getbalance(), balance1)
+ assert_equal(self.nodes[2].getbalance(), balance2)
+
+ # Backup to source wallet file must fail
+ sourcePaths = [
+ tmpdir + "/node0/regtest/wallets/wallet.dat",
+ tmpdir + "/node0/./regtest/wallets/wallet.dat",
+ tmpdir + "/node0/regtest/wallets/",
+ tmpdir + "/node0/regtest/wallets"]
+
+ for sourcePath in sourcePaths:
+ assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath)
+
+
+if __name__ == '__main__':
+ WalletBackupTest().main()