@@ -191,8 +191,13 @@ struct PubkeyProvider
191191 /* * Get the size of the generated public key(s) in bytes (33 or 65). */
192192 virtual size_t GetSize () const = 0;
193193
194+ enum class StringType {
195+ PUBLIC,
196+ COMPAT // string calculation that mustn't change over time to stay compatible with previous software versions
197+ };
198+
194199 /* * Get the descriptor string form. */
195- virtual std::string ToString () const = 0;
200+ virtual std::string ToString (StringType type=StringType::PUBLIC ) const = 0;
196201
197202 /* * Get the descriptor string form including private data (if available in arg). */
198203 virtual bool ToPrivateString (const SigningProvider& arg, std::string& out) const = 0;
@@ -212,9 +217,11 @@ class OriginPubkeyProvider final : public PubkeyProvider
212217 std::unique_ptr<PubkeyProvider> m_provider;
213218 bool m_apostrophe;
214219
215- std::string OriginString (bool normalized=false ) const
220+ std::string OriginString (StringType type, bool normalized=false ) const
216221 {
217- return HexStr (m_origin.fingerprint ) + FormatHDKeypath (m_origin.path , /* apostrophe=*/ !normalized && m_apostrophe);
222+ // If StringType==COMPAT, always use the apostrophe to stay compatible with previous versions
223+ bool use_apostrophe = (!normalized && m_apostrophe) || type == StringType::COMPAT;
224+ return HexStr (m_origin.fingerprint ) + FormatHDKeypath (m_origin.path , use_apostrophe);
218225 }
219226
220227public:
@@ -228,12 +235,12 @@ class OriginPubkeyProvider final : public PubkeyProvider
228235 }
229236 bool IsRange () const override { return m_provider->IsRange (); }
230237 size_t GetSize () const override { return m_provider->GetSize (); }
231- std::string ToString () const override { return " [" + OriginString () + " ]" + m_provider->ToString (); }
238+ std::string ToString (StringType type ) const override { return " [" + OriginString (type ) + " ]" + m_provider->ToString (type ); }
232239 bool ToPrivateString (const SigningProvider& arg, std::string& ret) const override
233240 {
234241 std::string sub;
235242 if (!m_provider->ToPrivateString (arg, sub)) return false ;
236- ret = " [" + OriginString () + " ]" + std::move (sub);
243+ ret = " [" + OriginString (StringType::PUBLIC ) + " ]" + std::move (sub);
237244 return true ;
238245 }
239246 bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
@@ -245,9 +252,9 @@ class OriginPubkeyProvider final : public PubkeyProvider
245252 // and append that to our own origin string.
246253 if (sub[0 ] == ' [' ) {
247254 sub = sub.substr (9 );
248- ret = " [" + OriginString (/* normalized=*/ true ) + std::move (sub);
255+ ret = " [" + OriginString (StringType::PUBLIC, /* normalized=*/ true ) + std::move (sub);
249256 } else {
250- ret = " [" + OriginString (/* normalized=*/ true ) + " ]" + std::move (sub);
257+ ret = " [" + OriginString (StringType::PUBLIC, /* normalized=*/ true ) + " ]" + std::move (sub);
251258 }
252259 return true ;
253260 }
@@ -275,7 +282,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
275282 }
276283 bool IsRange () const override { return false ; }
277284 size_t GetSize () const override { return m_pubkey.size (); }
278- std::string ToString () const override { return m_xonly ? HexStr (m_pubkey).substr (2 ) : HexStr (m_pubkey); }
285+ std::string ToString (StringType type ) const override { return m_xonly ? HexStr (m_pubkey).substr (2 ) : HexStr (m_pubkey); }
279286 bool ToPrivateString (const SigningProvider& arg, std::string& ret) const override
280287 {
281288 CKey key;
@@ -293,7 +300,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
293300 }
294301 bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
295302 {
296- ret = ToString ();
303+ ret = ToString (StringType::PUBLIC );
297304 return true ;
298305 }
299306 bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const override
@@ -421,19 +428,20 @@ class BIP32PubkeyProvider final : public PubkeyProvider
421428
422429 return true ;
423430 }
424- std::string ToString (bool normalized) const
431+ std::string ToString (StringType type, bool normalized) const
425432 {
426- const bool use_apostrophe = !normalized && m_apostrophe;
433+ // If StringType==COMPAT, always use the apostrophe to stay compatible with previous versions
434+ const bool use_apostrophe = (!normalized && m_apostrophe) || type == StringType::COMPAT;
427435 std::string ret = EncodeExtPubKey (m_root_extkey) + FormatHDKeypath (m_path, /* apostrophe=*/ use_apostrophe);
428436 if (IsRange ()) {
429437 ret += " /*" ;
430438 if (m_derive == DeriveType::HARDENED) ret += use_apostrophe ? ' \' ' : ' h' ;
431439 }
432440 return ret;
433441 }
434- std::string ToString () const override
442+ std::string ToString (StringType type=StringType::PUBLIC ) const override
435443 {
436- return ToString (/* normalized=*/ false );
444+ return ToString (type, /* normalized=*/ false );
437445 }
438446 bool ToPrivateString (const SigningProvider& arg, std::string& out) const override
439447 {
@@ -449,7 +457,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
449457 bool ToNormalizedString (const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
450458 {
451459 if (m_derive == DeriveType::HARDENED) {
452- out = ToString (/* normalized=*/ true );
460+ out = ToString (StringType::PUBLIC, /* normalized=*/ true );
453461
454462 return true ;
455463 }
@@ -556,6 +564,7 @@ class DescriptorImpl : public Descriptor
556564 PUBLIC,
557565 PRIVATE,
558566 NORMALIZED,
567+ COMPAT, // string calculation that mustn't change over time to stay compatible with previous software versions
559568 };
560569
561570 bool IsSolvable () const override
@@ -607,6 +616,9 @@ class DescriptorImpl : public Descriptor
607616 case StringType::PUBLIC:
608617 tmp = pubkey->ToString ();
609618 break ;
619+ case StringType::COMPAT:
620+ tmp = pubkey->ToString (PubkeyProvider::StringType::COMPAT);
621+ break ;
610622 }
611623 ret += tmp;
612624 }
@@ -617,10 +629,10 @@ class DescriptorImpl : public Descriptor
617629 return true ;
618630 }
619631
620- std::string ToString () const final
632+ std::string ToString (bool compat_format ) const final
621633 {
622634 std::string ret;
623- ToStringHelper (nullptr , ret, StringType::PUBLIC);
635+ ToStringHelper (nullptr , ret, compat_format ? StringType::COMPAT : StringType::PUBLIC);
624636 return AddChecksum (ret);
625637 }
626638
@@ -1778,6 +1790,14 @@ std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const Signing
17781790 return InferScript (script, ParseScriptContext::TOP, provider);
17791791}
17801792
1793+ uint256 DescriptorID (const Descriptor& desc)
1794+ {
1795+ std::string desc_str = desc.ToString (/* compat_format=*/ true );
1796+ uint256 id;
1797+ CSHA256 ().Write ((unsigned char *)desc_str.data (), desc_str.size ()).Finalize (id.begin ());
1798+ return id;
1799+ }
1800+
17811801void DescriptorCache::CacheParentExtPubKey (uint32_t key_exp_pos, const CExtPubKey& xpub)
17821802{
17831803 m_parent_xpubs[key_exp_pos] = xpub;
0 commit comments