Merge #13667: wallet: Fix backupwallet for multiwallets

a1a998cf24 wallet: Fix backupwallet for multiwallets (Daniel Kraft)

Pull request description:

  `backupwallet` was broken for multiwallets in their own directories (i.e. something like `DATADIR/wallets/mywallet/wallet.dat`).  In this case, the backup would use `DATADIR/wallets/wallet.dat` as source file and not take the specific wallet's directory into account.

  This led to either an error during the backup (if the wrong source file was not present) or would silently back up the wrong wallet; especially the latter behaviour can be quite bad for users.

Tree-SHA512: 7efe2450ca047e40719fcc7cc211ed94699056020ac737cada7b59e8240298675960570c45079add424d0aab520437d5050d956acd695a9c2452dd4317b4d2c4
This commit is contained in:
Wladimir J. van der Laan 2018-08-07 13:27:21 +02:00
commit b81a8a5ea9
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
2 changed files with 33 additions and 5 deletions

View file

@ -768,7 +768,7 @@ bool BerkeleyDatabase::Backup(const std::string& strDest)
env->mapFileUseCount.erase(strFile); env->mapFileUseCount.erase(strFile);
// Copy wallet file // Copy wallet file
fs::path pathSrc = GetWalletDir() / strFile; fs::path pathSrc = env->Directory() / strFile;
fs::path pathDest(strDest); fs::path pathDest(strDest);
if (fs::is_directory(pathDest)) if (fs::is_directory(pathDest))
pathDest /= strFile; pathDest /= strFile;

View file

@ -30,6 +30,11 @@ class MultiWalletTest(BitcoinTestFramework):
wallet_dir = lambda *p: data_dir('wallets', *p) wallet_dir = lambda *p: data_dir('wallets', *p)
wallet = lambda name: node.get_wallet_rpc(name) wallet = lambda name: node.get_wallet_rpc(name)
def wallet_file(name):
if os.path.isdir(wallet_dir(name)):
return wallet_dir(name, "wallet.dat")
return wallet_dir(name)
# check wallet.dat is created # check wallet.dat is created
self.stop_nodes() self.stop_nodes()
assert_equal(os.path.isfile(wallet_dir('wallet.dat')), True) assert_equal(os.path.isfile(wallet_dir('wallet.dat')), True)
@ -43,6 +48,12 @@ class MultiWalletTest(BitcoinTestFramework):
# directory paths) can be loaded # directory paths) can be loaded
os.rename(wallet_dir("wallet.dat"), wallet_dir("w8")) os.rename(wallet_dir("wallet.dat"), wallet_dir("w8"))
# create another dummy wallet for use in testing backups later
self.start_node(0, [])
self.stop_nodes()
empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat')
os.rename(wallet_dir("wallet.dat"), empty_wallet)
# restart node with a mix of wallet names: # restart node with a mix of wallet names:
# w1, w2, w3 - to verify new wallets created when non-existing paths specified # w1, w2, w3 - to verify new wallets created when non-existing paths specified
# w - to verify wallet name matching works when one wallet path is prefix of another # w - to verify wallet name matching works when one wallet path is prefix of another
@ -59,10 +70,7 @@ class MultiWalletTest(BitcoinTestFramework):
# check that all requested wallets were created # check that all requested wallets were created
self.stop_node(0) self.stop_node(0)
for wallet_name in wallet_names: for wallet_name in wallet_names:
if os.path.isdir(wallet_dir(wallet_name)): assert_equal(os.path.isfile(wallet_file(wallet_name)), True)
assert_equal(os.path.isfile(wallet_dir(wallet_name, "wallet.dat")), True)
else:
assert_equal(os.path.isfile(wallet_dir(wallet_name)), True)
# should not initialize if wallet path can't be created # should not initialize if wallet path can't be created
exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):" exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):"
@ -265,5 +273,25 @@ class MultiWalletTest(BitcoinTestFramework):
assert_equal(self.nodes[0].listwallets(), ['w1']) assert_equal(self.nodes[0].listwallets(), ['w1'])
assert_equal(w1.getwalletinfo()['walletname'], 'w1') assert_equal(w1.getwalletinfo()['walletname'], 'w1')
# Test backing up and restoring wallets
self.log.info("Test wallet backup")
self.restart_node(0, ['-nowallet'])
for wallet_name in wallet_names:
self.nodes[0].loadwallet(wallet_name)
for wallet_name in wallet_names:
rpc = self.nodes[0].get_wallet_rpc(wallet_name)
addr = rpc.getnewaddress()
backup = os.path.join(self.options.tmpdir, 'backup.dat')
rpc.backupwallet(backup)
self.nodes[0].unloadwallet(wallet_name)
shutil.copyfile(empty_wallet, wallet_file(wallet_name))
self.nodes[0].loadwallet(wallet_name)
assert_equal(rpc.getaddressinfo(addr)['ismine'], False)
self.nodes[0].unloadwallet(wallet_name)
shutil.copyfile(backup, wallet_file(wallet_name))
self.nodes[0].loadwallet(wallet_name)
assert_equal(rpc.getaddressinfo(addr)['ismine'], True)
if __name__ == '__main__': if __name__ == '__main__':
MultiWalletTest().main() MultiWalletTest().main()