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.
This commit is contained in:
Ava Chow
2026-08-25 15:14:48 -07:00
parent 1113f7590e
commit 62e826fa76
4 changed files with 22 additions and 5 deletions

View File

@@ -1634,7 +1634,7 @@ util::Result<void> 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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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