git / moonbite-core / test/functional/wallet_backup.py · raw

#!/usr/bin/env python3# Copyright (c) 2014-2020 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, thenMiner creates 100 blocks so 1 2 3 each have 50 maturecoins to spend.Then 5 iterations of 1/2/3 sending coins amongstthemselves 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 anytransaction fees paid mature.Sanity check:  Sum(1,2,3,4 balances) == 114*501/2/3 are shutdown, and their wallets erased.Then restore using wallet.dat backup. Andconfirm 1/2/3/4 balances are same as before.Shutdown again, restore using importwallet,and confirm again balances are correct."""from decimal import Decimalimport osfrom random import randintimport shutilfrom test_framework.test_framework import BitcoinTestFrameworkfrom test_framework.util import (    assert_equal,    assert_raises_rpc_error,)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        # whitelist all peers to speed up tx relay / mempool sync        self.extra_args = [            ["-whitelist=noban@127.0.0.1", "-keypool=100"],            ["-whitelist=noban@127.0.0.1", "-keypool=100"],            ["-whitelist=noban@127.0.0.1", "-keypool=100"],            ["-whitelist=noban@127.0.0.1"],        ]        self.rpc_timeout = 120    def skip_test_if_missing_module(self):        self.skip_if_no_wallet()    def setup_network(self):        self.setup_nodes()        self.connect_nodes(0, 3)        self.connect_nodes(1, 3)        self.connect_nodes(2, 3)        self.connect_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.        self.sync_mempools()        self.nodes[3].generate(1)        self.sync_blocks()    # As above, this mirrors the original bash test.    def start_three(self, args=()):        self.start_node(0, self.extra_args[0] + list(args))        self.start_node(1, self.extra_args[1] + list(args))        self.start_node(2, self.extra_args[2] + list(args))        self.connect_nodes(0, 3)        self.connect_nodes(1, 3)        self.connect_nodes(2, 3)        self.connect_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(os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))        os.remove(os.path.join(self.nodes[1].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))        os.remove(os.path.join(self.nodes[2].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))    def init_three(self):        self.init_wallet(0)        self.init_wallet(1)        self.init_wallet(2)    def run_test(self):        self.log.info("Generating initial blockchain")        self.nodes[0].generate(1)        self.sync_blocks()        self.nodes[1].generate(1)        self.sync_blocks()        self.nodes[2].generate(1)        self.sync_blocks()        self.nodes[3].generate(100)        self.sync_blocks()        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 _ in range(5):            self.do_one_round()        self.log.info("Backing up")        self.nodes[0].backupwallet(os.path.join(self.nodes[0].datadir, 'wallet.bak'))        self.nodes[1].backupwallet(os.path.join(self.nodes[1].datadir, 'wallet.bak'))        self.nodes[2].backupwallet(os.path.join(self.nodes[2].datadir, 'wallet.bak'))        if not self.options.descriptors:            self.nodes[0].dumpwallet(os.path.join(self.nodes[0].datadir, 'wallet.dump'))            self.nodes[1].dumpwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump'))            self.nodes[2].dumpwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump'))        self.log.info("More transactions")        for _ 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(os.path.join(self.nodes[2].datadir, self.chain, 'blocks'))        shutil.rmtree(os.path.join(self.nodes[2].datadir, self.chain, 'chainstate'))        # Restore wallets from backup        shutil.copyfile(os.path.join(self.nodes[0].datadir, 'wallet.bak'), os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))        shutil.copyfile(os.path.join(self.nodes[1].datadir, 'wallet.bak'), os.path.join(self.nodes[1].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))        shutil.copyfile(os.path.join(self.nodes[2].datadir, 'wallet.bak'), os.path.join(self.nodes[2].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename))        self.log.info("Re-starting nodes")        self.start_three()        self.sync_blocks()        assert_equal(self.nodes[0].getbalance(), balance0)        assert_equal(self.nodes[1].getbalance(), balance1)        assert_equal(self.nodes[2].getbalance(), balance2)        if not self.options.descriptors:            self.log.info("Restoring using dumped wallet")            self.stop_three()            self.erase_three()            #start node2 with no chain            shutil.rmtree(os.path.join(self.nodes[2].datadir, self.chain, 'blocks'))            shutil.rmtree(os.path.join(self.nodes[2].datadir, self.chain, 'chainstate'))            self.start_three(["-nowallet"])            self.init_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(os.path.join(self.nodes[0].datadir, 'wallet.dump'))            self.nodes[1].importwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump'))            self.nodes[2].importwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump'))            self.sync_blocks()            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 = [            os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename),            os.path.join(self.nodes[0].datadir, self.chain, '.', 'wallets', self.default_wallet_name, self.wallet_data_filename),            os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name),            os.path.join(self.nodes[0].datadir, self.chain, 'wallets')]        for sourcePath in sourcePaths:            assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath)if __name__ == '__main__':    WalletBackupTest().main()