From 93c039f02f34338f24c487ea46fc9b157f01fd2c Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 29 Nov 2023 12:02:38 -0300 Subject: [PATCH] test: add coverage for re-opening a downgraded encrypted wallet on master The test creates a wallet on master, downgrades and encrypts the wallet. Then, it tries to open it again on master. --- .../wallet_backwards_compatibility.py | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index fc1c61e56388f4..e1325b8510c43b 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -131,6 +131,66 @@ def test_v19_addmultisigaddress(self): wallet = node_v19.get_wallet_rpc("w1_v19") assert wallet.getaddressinfo(address_18075)["solvable"] + def test_downgrade_encryption(self, node_master, descriptors_nodes, legacy_nodes): + self.log.info("Test downgrade encryption + re-open on master") + + # Create wallet on master, downgrade and encrypt the wallet. Then, try to open it again on master. + name_wallet_on_master = "new_wallet" + node_master.createwallet(name_wallet_on_master, descriptors=self.options.descriptors) + wallet_on_master = node_master.get_wallet_rpc(name_wallet_on_master) + + # Retrieve the wallet's xpub + xpub = wallet_on_master.gethdkey()["xpub"] + + # Make a backup of the wallet file + backup_path = os.path.join(self.options.tmpdir, f"{name_wallet_on_master}.dat") + wallet_on_master.backupwallet(backup_path) + + # Downgrade and encrypt the wallet. + for node in descriptors_nodes if self.options.descriptors else legacy_nodes: + if self.major_version_less_than(node, 22): + continue # cannot downgrade further than v22, tr() descriptors aren't supported. + + # Load wallet in the prev node + target_dir = node.wallets_path / name_wallet_on_master + os.makedirs(target_dir, exist_ok=True) + shutil.copyfile(backup_path, target_dir / "wallet.dat") + node.loadwallet(name_wallet_on_master) + wallet_prev = node.get_wallet_rpc(name_wallet_on_master) + + # Encrypt wallet in the prev node + wallet_prev.encryptwallet("pass") + wallet_info = wallet_prev.getwalletinfo() + + # Restart prev node and verify it can reopen the wallet + self.restart_node(node.index, extra_args=[f"-wallet={name_wallet_on_master}"]) + wallet_prev = node.get_wallet_rpc(name_wallet_on_master) + assert_equal(wallet_info, wallet_prev.getwalletinfo()) + # And also it can decrypt the wallet + wallet_prev.walletpassphrase("pass", 999999) + + # Finally, export the encrypted prev node wallet, and re-open it on master + exported_name = f'{name_wallet_on_master}_{node.index}' + prev_backup_path = os.path.join(self.options.tmpdir, f"{exported_name}.dat") + wallet_prev.backupwallet(prev_backup_path) + + # Re-open it on master and decrypt the wallet + node_master.restorewallet(exported_name, prev_backup_path) + enc_wallet = node_master.get_wallet_rpc(exported_name) + enc_wallet.walletpassphrase("pass", 999999) + assert 'unlocked_until' in enc_wallet.getwalletinfo() + + # Check that the xpub is different + assert xpub != enc_wallet.gethdkey()["xpub"] + + # remove backup file + os.remove(prev_backup_path) + wallet_prev.unloadwallet() + enc_wallet.unloadwallet() + + # Clean wallet + wallet_on_master.unloadwallet() + def run_test(self): node_miner = self.nodes[0] node_master = self.nodes[1] @@ -305,6 +365,9 @@ def run_test(self): self.log.info("Test that 0.21 cannot open wallet containing tr() descriptors") assert_raises_rpc_error(-1, "map::at", node_v21.loadwallet, "w1") + # Test encryption on a previous version + reopen on master + self.test_downgrade_encryption(node_master, descriptors_nodes, legacy_nodes) + self.log.info("Test that a wallet can upgrade to and downgrade from master, from:") for node in descriptors_nodes if self.options.descriptors else legacy_nodes: # Run twice for each node to also test encrypted wallets