getdescriptorinfo describes its descriptor result as:
The descriptor in canonical form, without private keys.
The returned string is a re-serialisation of the parsed descriptor with private keys removed. It is not a canonical form: descriptors that describe the same wallet routinely come back as different strings with different checksums, and this is deliberate.
Three things the RPC does not canonicalise:
- The hardened derivation marker. #26076 added
m_apostropheso that the marker the caller used is preserved rather than rewritten (src/script/descriptor.cpp:262,:512); it first shipped in v26.0. Before that,FormatHDKeypath()emitted'unconditionally (v25.0,src/util/bip32.cpp:54), sohsupplied by the caller was rewritten — the behaviour #15740 objected to under the name "canonicalize". Where a single key expression mixes both markers, the style of its last hardened element is applied to the whole expression, which is still input-dependent. - Key order in
multi()/sortedmulti(). The order is preserved as given. Forsortedmulti()the written order carries no meaning at all, since BIP 383 sorts the derived keys when the output script is built, so the same wallet has n! equally valid descriptors. - The checksum. The
checksumfield is computed over the input string (src/rpc/output_script.cpp:215), so it can differ from the checksum embedded in the returneddescriptor— e.g. when a private key was supplied.
$ bitcoin-cli getdescriptorinfo "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)" | jq -r .descriptor
sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)#fne5696l
$ bitcoin-cli getdescriptorinfo "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)" | jq -r .descriptor
sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)#w5gau8hw
Both produce the same output script; neither is more canonical than the other. The same applies to the marker:
$ bitcoin-cli getdescriptorinfo "wpkh([f6bb4c63/0h/0h/30h]028429a37c3f09c8c5cc1fab58df32d1a7da7616c748a40eeb1aae1d64acb9c5cc)" | jq -r .descriptor
wpkh([f6bb4c63/0h/0h/30h]028429a37c3f09c8c5cc1fab58df32d1a7da7616c748a40eeb1aae1d64acb9c5cc)#vk9vfu0h
$ bitcoin-cli getdescriptorinfo "wpkh([f6bb4c63/0'/0'/30']028429a37c3f09c8c5cc1fab58df32d1a7da7616c748a40eeb1aae1d64acb9c5cc)" | jq -r .descriptor
wpkh([f6bb4c63/0'/0'/30']028429a37c3f09c8c5cc1fab58df32d1a7da7616c748a40eeb1aae1d64acb9c5cc)#5wdxpxcx
The wording dates from v0.18.0 (src/rpc/misc.cpp:153), where it did describe the behaviour, and has been carried forward unchanged since. Whether the RPC should canonicalise was settled in #15740 in favour of round-tripping what the caller supplied; this only brings the description into line with that outcome.
I have deliberately not replaced the phrase with "normal form" or "normalized". Those terms already denote a different transformation in this codebase — BIP 380's "Normalization of Key Expressions with Hardened Derivation", implemented as Descriptor::ToNormalizedString() ("Normalized descriptors have the xpub at the last hardened step", src/script/descriptor.h:140) — which getdescriptorinfo does not perform. Dropping the qualifier avoids the collision.
Documentation only; no behaviour change. The phrase occurs nowhere else in the repo.
-{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys. For a multipath descriptor, only the first will be returned."},
+{RPCResult::Type::STR, "descriptor", "The descriptor, without private keys. For a multipath descriptor, only the first will be returned."},
If reviewers would rather the help positively state what is preserved (hardened marker and key order as supplied, checksum recomputed), I am happy to expand it; I have kept the change minimal.