From 62e826fa76172210572356eef9fa3cd3309baf56 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Tue, 25 Aug 2026 15:14:48 -0700 Subject: [PATCH] wallet: Update WalletDescriptor from another one instead of overwriting If a descriptor is being reimported, we should only update the metadata and cache from the other one, rather than overwriting the entire thing. This avoids a potential issue where the on-disk record is overwritten with a backwards incompatible string. --- src/wallet/scriptpubkeyman.cpp | 2 +- src/wallet/walletutil.cpp | 12 ++++++++++++ src/wallet/walletutil.h | 2 ++ test/functional/wallet_backwards_compatibility.py | 11 +++++++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index a7d7bc68cad..481d23f7dd3 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1634,7 +1634,7 @@ util::Result DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescr m_map_pubkeys.clear(); m_map_script_pub_keys.clear(); m_max_cached_index = -1; - m_wallet_descriptor = descriptor; + m_wallet_descriptor.UpdateFrom(descriptor); WalletBatch batch(m_storage.GetDatabase()); UpdateWithSigningProvider(batch, provider); diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 85249f63275..9b0c2378a08 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -85,4 +85,16 @@ WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const Ou return w_desc; } +void WalletDescriptor::UpdateFrom(const WalletDescriptor& other) +{ + if (descriptor->ToCanonicalString() != other.descriptor->ToCanonicalString()) { + return; + } + range_start = other.range_start; + next_index = other.next_index; + range_end = other.range_end; + creation_time = other.creation_time; + cache = other.cache; +} + } // namespace wallet diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index a85a339a2da..6e50c283dd4 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -128,6 +128,8 @@ public: descriptor(descriptor), id(DescriptorID(*descriptor)), creation_time(creation_time) {} + + void UpdateFrom(const WalletDescriptor& other); }; WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const OutputType& output_type, bool internal); diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index 9ae87c019b8..a16ae07bd3e 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -328,9 +328,12 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): node_master.createwallet(wallet_name="miniscript") wallet = node_master.get_wallet_rpc("miniscript") - miniscript_desc = descsum_create("wsh(or_b(pk([deadbeef/0h/1h/2h]tprv8ZgxMBicQKsPerQj6m35no46amfKQdjY7AhLnmatHYXs8S4MTgeZYkWAn4edSGwwL3vkSiiGqSZQrmy5D3P5gBoqgvYP2fCUpBwbKTMTAkL/3h/*),s:pk([beefdead/4h/5h]tpubD6NzVbkrYhZ4YU9vM1s53UhD75UyJatx8EMzMZ3VUjR2FciNfLLkAw6a4pWACChzobTseNqdWk4G7ZdBqRDLtLSACKykTScmqibb1ZrCvJu/6/7/*)))") - res = wallet.importdescriptors([{"desc": miniscript_desc, "timestamp":"now"}]) - assert_equal(res[0]["success"], True) + miniscript_desc = "wsh(or_b(pk([deadbeef/0h/1h/2h]tprv8ZgxMBicQKsPerQj6m35no46amfKQdjY7AhLnmatHYXs8S4MTgeZYkWAn4edSGwwL3vkSiiGqSZQrmy5D3P5gBoqgvYP2fCUpBwbKTMTAkL/3h/*),s:pk([beefdead/4h/5h]tpubD6NzVbkrYhZ4YU9vM1s53UhD75UyJatx8EMzMZ3VUjR2FciNfLLkAw6a4pWACChzobTseNqdWk4G7ZdBqRDLtLSACKykTScmqibb1ZrCvJu/6/7/*)))" + miniscript_apos = miniscript_desc.replace("[beefdead/4h/5h]", "[beefdead/4'/5']") + assert miniscript_apos != miniscript_desc + for desc in [miniscript_desc, miniscript_apos]: + res = wallet.importdescriptors([{"desc": descsum_create(desc), "timestamp":"now"}]) + assert_equal(res[0]["success"], True) # Unload wallets and copy to older nodes: node_master_wallets_dir = node_master.wallets_path @@ -425,7 +428,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): pubkey = addr_info["pubkey"] if self.major_version_at_least(node, 24): - res = wallet_prev.importdescriptors([{"desc": miniscript_desc, "timestamp":"now"}]) + res = wallet_prev.importdescriptors([{"desc": descsum_create(miniscript_desc), "timestamp":"now"}]) assert_equal(res[0]["success"], True) # Make a backup of the wallet file