Skip to content

Commit 9ea84c0

Browse files
furszyachow101
authored andcommitted
test: restorewallet, coverage for existing dirs, unnamed wallet and prune failure
The first test verifies that restoring into an existing empty directory or a directory with no .dat db files succeeds, while restoring into a dir with a .dat file fails. The second test covers restoring into the default unnamed wallet (wallet.dat), which also implicitly exercises the recovery path used after a failed migration. The third test covers failure during restore on a prune node. When the wallet last sync was beyond the pruning height. Github-Pull: #34156 Rebased-From: f011e0f
1 parent 833848e commit 9ea84c0

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

test/functional/wallet_backup.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from test_framework.util import (
4141
assert_equal,
4242
assert_raises_rpc_error,
43+
sha256sum_file,
4344
)
4445

4546

@@ -140,6 +141,67 @@ def restore_wallet_existent_name(self):
140141
assert_raises_rpc_error(-36, error_message, node.restorewallet, wallet_name, backup_file)
141142
assert wallet_file.exists()
142143

144+
def test_restore_existent_dir(self):
145+
self.log.info("Test restore on an existent empty directory")
146+
node = self.nodes[3]
147+
backup_file = self.nodes[0].datadir_path / 'wallet.bak'
148+
wallet_name = "restored_wallet"
149+
wallet_dir = node.wallets_path / wallet_name
150+
os.mkdir(wallet_dir)
151+
res = node.restorewallet(wallet_name, backup_file)
152+
assert_equal(res['name'], wallet_name)
153+
node.unloadwallet(wallet_name)
154+
155+
self.log.info("Test restore succeeds when the target directory contains non-wallet files")
156+
wallet_file = node.wallets_path / wallet_name / "wallet.dat"
157+
os.remove(wallet_file)
158+
extra_file = node.wallets_path / wallet_name / "not_a_wallet.txt"
159+
extra_file.touch()
160+
res = node.restorewallet(wallet_name, backup_file)
161+
assert_equal(res['name'], wallet_name)
162+
assert extra_file.exists() # extra file was not removed by mistake
163+
node.unloadwallet(wallet_name)
164+
165+
self.log.info("Test restore failure due to existing db file in the destination directory")
166+
original_shasum = sha256sum_file(wallet_file)
167+
error_message = "Failed to restore wallet. Database file exists in '{}'.".format(wallet_dir / "wallet.dat")
168+
assert_raises_rpc_error(-36, error_message, node.restorewallet, wallet_name, backup_file)
169+
# Ensure the wallet file remains untouched
170+
assert wallet_dir.exists()
171+
assert_equal(original_shasum, sha256sum_file(wallet_file))
172+
173+
self.log.info("Test restore succeeds when the .dat file in the destination has a different name")
174+
second_wallet = wallet_dir / "hidden_storage.dat"
175+
os.rename(wallet_dir / "wallet.dat", second_wallet)
176+
original_shasum = sha256sum_file(second_wallet)
177+
res = node.restorewallet(wallet_name, backup_file)
178+
assert_equal(res['name'], wallet_name)
179+
assert (wallet_dir / "hidden_storage.dat").exists()
180+
assert_equal(original_shasum, sha256sum_file(second_wallet))
181+
node.unloadwallet(wallet_name)
182+
183+
# Clean for follow-up tests
184+
os.remove(wallet_file)
185+
186+
def test_restore_into_unnamed_wallet(self):
187+
self.log.info("Test restore into a default unnamed wallet")
188+
# This is also useful to test the migration recovery after failure logic
189+
node = self.nodes[3]
190+
if not self.options.descriptors:
191+
node.unloadwallet("")
192+
os.rename(node.wallets_path / "wallet.dat", node.wallets_path / "default.wallet.dat")
193+
backup_file = self.nodes[0].datadir_path / 'wallet.bak'
194+
wallet_name = ""
195+
res = node.restorewallet(wallet_name, backup_file)
196+
assert_equal(res['name'], "")
197+
assert (node.wallets_path / "wallet.dat").exists()
198+
# Clean for follow-up tests
199+
node.unloadwallet("")
200+
os.remove(node.wallets_path / "wallet.dat")
201+
if not self.options.descriptors:
202+
os.rename(node.wallets_path / "default.wallet.dat", node.wallets_path / "wallet.dat")
203+
node.loadwallet("")
204+
143205
def test_pruned_wallet_backup(self):
144206
self.log.info("Test loading backup on a pruned node when the backup was created close to the prune height of the restoring node")
145207
node = self.nodes[3]
@@ -159,6 +221,19 @@ def test_pruned_wallet_backup(self):
159221
# the backup to load successfully this close to the prune height
160222
node.restorewallet('pruned', node.datadir_path / 'wallet_pruned.bak')
161223

224+
self.log.info("Test restore on a pruned node when the backup was beyond the pruning point")
225+
if not self.options.descriptors:
226+
node.unloadwallet("")
227+
os.rename(node.wallets_path / "wallet.dat", node.wallets_path / "default.wallet.dat")
228+
backup_file = self.nodes[0].datadir_path / 'wallet.bak'
229+
wallet_name = ""
230+
error_message = "Wallet loading failed. Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"
231+
assert_raises_rpc_error(-4, error_message, node.restorewallet, wallet_name, backup_file)
232+
assert node.wallets_path.exists() # ensure the wallets dir exists
233+
if not self.options.descriptors:
234+
os.rename(node.wallets_path / "default.wallet.dat", node.wallets_path / "wallet.dat")
235+
node.loadwallet("")
236+
162237
def run_test(self):
163238
self.log.info("Generating initial blockchain")
164239
self.generate(self.nodes[0], 1)
@@ -227,6 +302,8 @@ def run_test(self):
227302
assert_equal(res2_rpc.getbalance(), balance2)
228303

229304
self.restore_wallet_existent_name()
305+
self.test_restore_existent_dir()
306+
self.test_restore_into_unnamed_wallet()
230307

231308
if not self.options.descriptors:
232309
self.log.info("Restoring using dumped wallet")

0 commit comments

Comments
 (0)