AI-generated analysisPublished automatically and not human-verified. Validated context appears in community notes below.
← Watch feed
Moderate 57 Bitcoin

Merge bitcoin/bitcoin#35445: wallet, descriptor: Revert `StringType::COMPAT` for Miniscript expressions and drop the concept of a Descriptor ID that can be validated

Public commit record

What the developer wrote

Authored by merge-script

100/100 · Strong
Merge bitcoin/bitcoin#35445: wallet, descriptor: Revert `StringType::COMPAT` for Miniscript expressions and drop the concept of a Descriptor ID that can be validated

ec2adf3c51ca7322307be3d052bc0e9fa4332dd2 test: Check miniscript descriptor h and apostrophe equivalence (w0xlt)
a2d001b57c5f7adc6649e96fc2254d729f4ba750 test: Enforce descriptor reimport is an update (Ava Chow)
e2b2f1c5c6f720381b8cc182e750aadd703e4b4f descriptor: Rename DescriptorID to CompatDescriptorHash (Ava Chow)
6ad31c062c70101fe6463fe516de7edc651881be test: Add 31.0 to wallet backwards compatibility test (Ava Chow)
2a6c53371be770f7e945316481b231dcbed01dd9 wallet, spkm: Treat Descriptor ID as an opaque SPKM ID (Ava Chow)
62e826fa76172210572356eef9fa3cd3309baf56 wallet: Update WalletDescriptor from another one instead of overwriting (Ava Chow)
1113f7590ed095ec09a1d483f8c1ee5d54f0b0df wallet, export: Include descriptor cache when exporting descriptors (Ava Chow)
9fc7b2618b6abb0d79e794f34f16bebf74bbbe6a spkm: Remove DescriptorSPKM constructor that doesn't take a descriptor (Ava Chow)
770ff64bd7fd52e2c3d2634dc55046c5137cbe86 test: Add v30.2 and Miniscript to wallet backwards compatibility test (Ava Chow)
35d6a60dbf5a3424804430041f5f4091efb82b6c descriptor: Add ToCanonicalString (Ava Chow)
1d87af26ce1402d6fbc1db855434c36d0f7bd0c2 descriptors: Remove default StringType from PubkeyProvider::ToString() (Ava Chow)
1c7f9aaf758f6c8580a889fa6af675e6b365dbbf miniscript: Don't use StringType::COMPAT (Ava Chow)

Pull request description:

Since keys in Miniscript expressions were not correctly handling `StringType::COMPAT` when generating the Descriptor ID, in order to keep compatibility with previous versions, we need to continue to handle that enum incorrectly when computing the ID.

Given that this it the second time that we have had this issue, this PR also drops the concept of Descriptor ID being something that we can validate. Instead, the ID read in from the database is treated as an opaque blob that is used only to tie together the records related to a particular SPKM. It is instead treated as a ScriptPubKeyMan ID and users of it must be retrieving the ID from somewhere rather than computing it from a descriptor. The check of comparing the read ID to the computed ID is removed so that all previously created wallets can be read.

To clarify that the ID is not actually an ID, the function `DescriptorID` is renamed to `CompatDescriptorHash` and it is still used to generate the SPKM ID that is written to the database.

The ID was additionally being used to determine whether a descriptor is equal to another descriptor. This was used only by `importdescriptors` and `createwalletdescriptor`. These uses have been changed to do a string comparison rather than computing a hash and comparing the hashes. This removes the need to rely on `CompatDescriptorHash`.

The only caveat is that previously the hash was being used to do a map lookup in `m_spk_managers`, but this is now changed to use `std::find_if`. The lookup complexity changes from logarithmic to linear, which may be really bad for wallets with a lot of descriptors, e.g. migrated formerly non-HD wallets. I think in general though, the tradeoff is okay, and neither of these functions purport to be performant, especially as `importdescriptors` may also do a rescan which can take a long time. However, if that is a concern, an additional map of `CompatDescriptorHash` to DescriptorSPKM can be added.

Lastly, the wallet backwards compatibility test is updated to have 30.2 and 31.0 nodes, and a wallet with miniscript expressions. This exercises both creating wallets in previous versions and making sure they load in master, and making new wallets on master and checking whether they load, depending on the version.

Fixes #35432

ACKs for top commit:
pseudoramdom:
ACK ec2adf3c51ca7322307be3d052bc0e9fa4332dd2
davidgumberg:
crACK https://github.com/bitcoin/bitcoin/commit/ec2adf3c51ca7322307be3d052bc0e9fa4332dd2
w0xlt:
ACK ec2adf3c51ca7322307be3d052bc0e9fa4332dd2

Tree-SHA512: a32995c171b829a874cfd1bb03adde46fd8737322d5c44bc2ff27eff1ea8742c16c7ea1bb6fdc0fb2b89d0f11919850383799c3af126e7f55fe0878a8f1a7024
✓ Specific, descriptive subject✓ Names a concrete action or component✓ Provides detailed explanatory context✓ Explains rationale or failure mode✓ Mentions testing or verification✓ Links an issue, advisory, or supporting reference
The short version

What changed, and why it matters

This Bitcoin Core update fixes a wallet bug where certain newer-style descriptors (called Miniscript) could not be loaded after being created in older versions. The root cause was an internal ID that was computed differently for Miniscript than for other descriptors. Rather than keep trying to make the ID match perfectly, the developers changed the wallet to treat the stored ID as an opaque label and compare descriptors by their text instead. This prevents 'wallet corrupted' errors and allows older wallets to load safely. It is a backward-compatibility and robustness fix, not a remote-exploitable vulnerability.

Recommended action

Users running descriptor wallets with Miniscript should upgrade to the version containing this fix to avoid 'wallet corrupted' load failures. Wallet developers should avoid relying on DescriptorID/CompatDescriptorHash for validation or equality checks and use canonical descriptor strings instead. No immediate emergency action is required; this is a compatibility/robustness fix rather than a remote-exploitable security flaw.

Security signals we found

01

Fixes wallet load failure (DBErrors::CORRUPT) for Miniscript descriptors created in prior versions

02

Removes validation of stored descriptor ID against recomputed hash

03

Switches descriptor equality checks from hash comparison to canonical string comparison

04

Adds backward-compatibility test coverage for v30.2 and v31.0 with Miniscript descriptors

05

Includes descriptor cache in export data to preserve non-self-expanding descriptors

Risk score

Why this scored 57/100

Our methodology →
Potential impact 18/30
Exploitability 8/25
Stealth signal 7/15
Affected reach 12/15
Confidence 8/10
Evidence quality 4/5
Human-validated context

Community notes

Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.

No validated notes yet.

The AI analysis stands alone for now. Submit a note if you can add evidence or important context.