@@ -181,7 +181,7 @@ struct PubkeyProvider
181
181
virtual bool ToPrivateString (const SigningProvider& arg, std::string& out) const = 0;
182
182
183
183
/* * Get the descriptor string form with the xpub at the last hardened derivation */
184
- virtual bool ToNormalizedString (const SigningProvider& arg, std::string& out) const = 0;
184
+ virtual bool ToNormalizedString (const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr ) const = 0;
185
185
186
186
/* * Derive a private key, if private data is available in arg. */
187
187
virtual bool GetPrivKey (int pos, const SigningProvider& arg, CKey& key) const = 0;
@@ -216,10 +216,10 @@ class OriginPubkeyProvider final : public PubkeyProvider
216
216
ret = " [" + OriginString () + " ]" + std::move (sub);
217
217
return true ;
218
218
}
219
- bool ToNormalizedString (const SigningProvider& arg, std::string& ret) const override
219
+ bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache ) const override
220
220
{
221
221
std::string sub;
222
- if (!m_provider->ToNormalizedString (arg, sub)) return false ;
222
+ if (!m_provider->ToNormalizedString (arg, sub, cache )) return false ;
223
223
// If m_provider is a BIP32PubkeyProvider, we may get a string formatted like a OriginPubkeyProvider
224
224
// In that case, we need to strip out the leading square bracket and fingerprint from the substring,
225
225
// and append that to our own origin string.
@@ -263,7 +263,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
263
263
ret = EncodeSecret (key);
264
264
return true ;
265
265
}
266
- bool ToNormalizedString (const SigningProvider& arg, std::string& ret) const override
266
+ bool ToNormalizedString (const SigningProvider& arg, std::string& ret, const DescriptorCache* cache ) const override
267
267
{
268
268
ret = ToString ();
269
269
return true ;
@@ -412,7 +412,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
412
412
}
413
413
return true ;
414
414
}
415
- bool ToNormalizedString (const SigningProvider& arg, std::string& out) const override
415
+ bool ToNormalizedString (const SigningProvider& arg, std::string& out, const DescriptorCache* cache ) const override
416
416
{
417
417
// For hardened derivation type, just return the typical string, nothing to normalize
418
418
if (m_derive == DeriveType::HARDENED) {
@@ -431,29 +431,39 @@ class BIP32PubkeyProvider final : public PubkeyProvider
431
431
out = ToString ();
432
432
return true ;
433
433
}
434
- // Derive the xpub at the last hardened step
435
- CExtKey xprv;
436
- if (!GetExtKey (arg, xprv)) return false ;
434
+ // Get the path to the last hardened stup
437
435
KeyOriginInfo origin;
438
436
int k = 0 ;
439
437
for (; k <= i; ++k) {
440
- // Derive
441
- xprv.Derive (xprv, m_path.at (k));
442
438
// Add to the path
443
439
origin.path .push_back (m_path.at (k));
444
- // First derivation element, get the fingerprint for origin
445
- if (k == 0 ) {
446
- std::copy (xprv.vchFingerprint , xprv.vchFingerprint + 4 , origin.fingerprint );
447
- }
448
440
}
449
441
// Build the remaining path
450
442
KeyPath end_path;
451
443
for (; k < (int )m_path.size (); ++k) {
452
444
end_path.push_back (m_path.at (k));
453
445
}
446
+ // Get the fingerprint
447
+ CKeyID id = m_root_extkey.pubkey .GetID ();
448
+ std::copy (id.begin (), id.begin () + 4 , origin.fingerprint );
449
+
450
+ CExtPubKey xpub;
451
+ CExtKey lh_xprv;
452
+ // If we have the cache, just get the parent xpub
453
+ if (cache != nullptr ) {
454
+ cache->GetCachedLastHardenedExtPubKey (m_expr_index, xpub);
455
+ }
456
+ if (!xpub.pubkey .IsValid ()) {
457
+ // Cache miss, or nor cache, or need privkey
458
+ CExtKey xprv;
459
+ if (!GetDerivedExtKey (arg, xprv, lh_xprv)) return false ;
460
+ xpub = lh_xprv.Neuter ();
461
+ }
462
+ assert (xpub.pubkey .IsValid ());
463
+
454
464
// Build the string
455
465
std::string origin_str = HexStr (origin.fingerprint ) + FormatHDKeypath (origin.path );
456
- out = " [" + origin_str + " ]" + EncodeExtPubKey (xprv. Neuter () ) + FormatHDKeypath (end_path);
466
+ out = " [" + origin_str + " ]" + EncodeExtPubKey (xpub ) + FormatHDKeypath (end_path);
457
467
if (IsRange ()) {
458
468
out += " /*" ;
459
469
assert (m_derive == DeriveType::UNHARDENED);
@@ -533,19 +543,19 @@ class DescriptorImpl : public Descriptor
533
543
return false ;
534
544
}
535
545
536
- virtual bool ToStringSubScriptHelper (const SigningProvider* arg, std::string& ret, const StringType type) const
546
+ virtual bool ToStringSubScriptHelper (const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr ) const
537
547
{
538
548
size_t pos = 0 ;
539
549
for (const auto & scriptarg : m_subdescriptor_args) {
540
550
if (pos++) ret += " ," ;
541
551
std::string tmp;
542
- if (!scriptarg->ToStringHelper (arg, tmp, type)) return false ;
552
+ if (!scriptarg->ToStringHelper (arg, tmp, type, cache )) return false ;
543
553
ret += std::move (tmp);
544
554
}
545
555
return true ;
546
556
}
547
557
548
- bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type) const
558
+ bool ToStringHelper (const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr ) const
549
559
{
550
560
std::string extra = ToStringExtra ();
551
561
size_t pos = extra.size () > 0 ? 1 : 0 ;
@@ -555,7 +565,7 @@ class DescriptorImpl : public Descriptor
555
565
std::string tmp;
556
566
switch (type) {
557
567
case StringType::NORMALIZED:
558
- if (!pubkey->ToNormalizedString (*arg, tmp)) return false ;
568
+ if (!pubkey->ToNormalizedString (*arg, tmp, cache )) return false ;
559
569
break ;
560
570
case StringType::PRIVATE:
561
571
if (!pubkey->ToPrivateString (*arg, tmp)) return false ;
@@ -567,7 +577,7 @@ class DescriptorImpl : public Descriptor
567
577
ret += std::move (tmp);
568
578
}
569
579
std::string subscript;
570
- if (!ToStringSubScriptHelper (arg, subscript, type)) return false ;
580
+ if (!ToStringSubScriptHelper (arg, subscript, type, cache )) return false ;
571
581
if (pos && subscript.size ()) ret += ' ,' ;
572
582
out = std::move (ret) + std::move (subscript) + " )" ;
573
583
return true ;
@@ -587,9 +597,9 @@ class DescriptorImpl : public Descriptor
587
597
return ret;
588
598
}
589
599
590
- bool ToNormalizedString (const SigningProvider& arg, std::string& out) const override final
600
+ bool ToNormalizedString (const SigningProvider& arg, std::string& out, const DescriptorCache* cache ) const override final
591
601
{
592
- bool ret = ToStringHelper (&arg, out, StringType::NORMALIZED);
602
+ bool ret = ToStringHelper (&arg, out, StringType::NORMALIZED, cache );
593
603
out = AddChecksum (out);
594
604
return ret;
595
605
}
@@ -843,7 +853,7 @@ class TRDescriptor final : public DescriptorImpl
843
853
out.tr_spenddata [output].Merge (builder.GetSpendData ());
844
854
return Vector (GetScriptForDestination (output));
845
855
}
846
- bool ToStringSubScriptHelper (const SigningProvider* arg, std::string& ret, const StringType type) const override
856
+ bool ToStringSubScriptHelper (const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr ) const override
847
857
{
848
858
if (m_depths.empty ()) return true ;
849
859
std::vector<bool > path;
@@ -854,7 +864,7 @@ class TRDescriptor final : public DescriptorImpl
854
864
path.push_back (false );
855
865
}
856
866
std::string tmp;
857
- if (!m_subdescriptor_args[pos]->ToStringHelper (arg, tmp, type)) return false ;
867
+ if (!m_subdescriptor_args[pos]->ToStringHelper (arg, tmp, type, cache )) return false ;
858
868
ret += std::move (tmp);
859
869
while (!path.empty () && path.back ()) {
860
870
if (path.size () > 1 ) ret += ' }' ;
0 commit comments