@@ -191,8 +191,13 @@ struct PubkeyProvider
191
191
/* * Get the size of the generated public key(s) in bytes (33 or 65). */
192
192
virtual size_t GetSize () const = 0;
193
193
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
+
194
199
/* * Get the descriptor string form. */
195
- virtual std::string ToString () const = 0;
200
+ virtual std::string ToString (StringType type=StringType::PUBLIC ) const = 0;
196
201
197
202
/* * Get the descriptor string form including private data (if available in arg). */
198
203
virtual bool ToPrivateString (const SigningProvider& arg, std::string& out) const = 0;
@@ -212,9 +217,11 @@ class OriginPubkeyProvider final : public PubkeyProvider
212
217
std::unique_ptr<PubkeyProvider> m_provider;
213
218
bool m_apostrophe;
214
219
215
- std::string OriginString (bool normalized=false ) const
220
+ std::string OriginString (StringType type, bool normalized=false ) const
216
221
{
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);
218
225
}
219
226
220
227
public:
@@ -228,12 +235,12 @@ class OriginPubkeyProvider final : public PubkeyProvider
228
235
}
229
236
bool IsRange () const override { return m_provider->IsRange (); }
230
237
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 ); }
232
239
bool ToPrivateString (const SigningProvider& arg, std::string& ret) const override
233
240
{
234
241
std::string sub;
235
242
if (!m_provider->ToPrivateString (arg, sub)) return false ;
236
- ret = " [" + OriginString () + " ]" + std::move (sub);
243
+ ret = " [" + OriginString (StringType::PUBLIC ) + " ]" + std::move (sub);
237
244
return true ;
238
245
}
239
246
bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
@@ -245,9 +252,9 @@ class OriginPubkeyProvider final : public PubkeyProvider
245
252
// and append that to our own origin string.
246
253
if (sub[0 ] == ' [' ) {
247
254
sub = sub.substr (9 );
248
- ret = " [" + OriginString (/* normalized=*/ true ) + std::move (sub);
255
+ ret = " [" + OriginString (StringType::PUBLIC, /* normalized=*/ true ) + std::move (sub);
249
256
} else {
250
- ret = " [" + OriginString (/* normalized=*/ true ) + " ]" + std::move (sub);
257
+ ret = " [" + OriginString (StringType::PUBLIC, /* normalized=*/ true ) + " ]" + std::move (sub);
251
258
}
252
259
return true ;
253
260
}
@@ -275,7 +282,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
275
282
}
276
283
bool IsRange () const override { return false ; }
277
284
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); }
279
286
bool ToPrivateString (const SigningProvider& arg, std::string& ret) const override
280
287
{
281
288
CKey key;
@@ -293,7 +300,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
293
300
}
294
301
bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
295
302
{
296
- ret = ToString ();
303
+ ret = ToString (StringType::PUBLIC );
297
304
return true ;
298
305
}
299
306
bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const override
@@ -421,19 +428,20 @@ class BIP32PubkeyProvider final : public PubkeyProvider
421
428
422
429
return true ;
423
430
}
424
- std::string ToString (bool normalized) const
431
+ std::string ToString (StringType type, bool normalized) const
425
432
{
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;
427
435
std::string ret = EncodeExtPubKey (m_root_extkey) + FormatHDKeypath (m_path, /* apostrophe=*/ use_apostrophe);
428
436
if (IsRange ()) {
429
437
ret += " /*" ;
430
438
if (m_derive == DeriveType::HARDENED) ret += use_apostrophe ? ' \' ' : ' h' ;
431
439
}
432
440
return ret;
433
441
}
434
- std::string ToString () const override
442
+ std::string ToString (StringType type=StringType::PUBLIC ) const override
435
443
{
436
- return ToString (/* normalized=*/ false );
444
+ return ToString (type, /* normalized=*/ false );
437
445
}
438
446
bool ToPrivateString (const SigningProvider& arg, std::string& out) const override
439
447
{
@@ -449,7 +457,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
449
457
bool ToNormalizedString (const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
450
458
{
451
459
if (m_derive == DeriveType::HARDENED) {
452
- out = ToString (/* normalized=*/ true );
460
+ out = ToString (StringType::PUBLIC, /* normalized=*/ true );
453
461
454
462
return true ;
455
463
}
@@ -556,6 +564,7 @@ class DescriptorImpl : public Descriptor
556
564
PUBLIC,
557
565
PRIVATE,
558
566
NORMALIZED,
567
+ COMPAT, // string calculation that mustn't change over time to stay compatible with previous software versions
559
568
};
560
569
561
570
bool IsSolvable () const override
@@ -607,6 +616,9 @@ class DescriptorImpl : public Descriptor
607
616
case StringType::PUBLIC:
608
617
tmp = pubkey->ToString ();
609
618
break ;
619
+ case StringType::COMPAT:
620
+ tmp = pubkey->ToString (PubkeyProvider::StringType::COMPAT);
621
+ break ;
610
622
}
611
623
ret += tmp;
612
624
}
@@ -617,10 +629,10 @@ class DescriptorImpl : public Descriptor
617
629
return true ;
618
630
}
619
631
620
- std::string ToString () const final
632
+ std::string ToString (bool compat_format ) const final
621
633
{
622
634
std::string ret;
623
- ToStringHelper (nullptr , ret, StringType::PUBLIC);
635
+ ToStringHelper (nullptr , ret, compat_format ? StringType::COMPAT : StringType::PUBLIC);
624
636
return AddChecksum (ret);
625
637
}
626
638
@@ -1778,6 +1790,14 @@ std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const Signing
1778
1790
return InferScript (script, ParseScriptContext::TOP, provider);
1779
1791
}
1780
1792
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
+
1781
1801
void DescriptorCache::CacheParentExtPubKey (uint32_t key_exp_pos, const CExtPubKey& xpub)
1782
1802
{
1783
1803
m_parent_xpubs[key_exp_pos] = xpub;
0 commit comments