Skip to content

Commit 3280704

Browse files
committed
Pass in DescriptorCache to ToNormalizedString
Use the descriptor xpub cache in ToNormalizedString so that the wallet does not need to be unlocked in order to get the normalized descriptor.
1 parent 7a26ff1 commit 3280704

File tree

3 files changed

+36
-26
lines changed

3 files changed

+36
-26
lines changed

src/script/descriptor.cpp

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ struct PubkeyProvider
181181
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
182182

183183
/** 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;
185185

186186
/** Derive a private key, if private data is available in arg. */
187187
virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
@@ -216,10 +216,10 @@ class OriginPubkeyProvider final : public PubkeyProvider
216216
ret = "[" + OriginString() + "]" + std::move(sub);
217217
return true;
218218
}
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
220220
{
221221
std::string sub;
222-
if (!m_provider->ToNormalizedString(arg, sub)) return false;
222+
if (!m_provider->ToNormalizedString(arg, sub, cache)) return false;
223223
// If m_provider is a BIP32PubkeyProvider, we may get a string formatted like a OriginPubkeyProvider
224224
// In that case, we need to strip out the leading square bracket and fingerprint from the substring,
225225
// and append that to our own origin string.
@@ -263,7 +263,7 @@ class ConstPubkeyProvider final : public PubkeyProvider
263263
ret = EncodeSecret(key);
264264
return true;
265265
}
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
267267
{
268268
ret = ToString();
269269
return true;
@@ -412,7 +412,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
412412
}
413413
return true;
414414
}
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
416416
{
417417
// For hardened derivation type, just return the typical string, nothing to normalize
418418
if (m_derive == DeriveType::HARDENED) {
@@ -431,29 +431,39 @@ class BIP32PubkeyProvider final : public PubkeyProvider
431431
out = ToString();
432432
return true;
433433
}
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
437435
KeyOriginInfo origin;
438436
int k = 0;
439437
for (; k <= i; ++k) {
440-
// Derive
441-
xprv.Derive(xprv, m_path.at(k));
442438
// Add to the path
443439
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-
}
448440
}
449441
// Build the remaining path
450442
KeyPath end_path;
451443
for (; k < (int)m_path.size(); ++k) {
452444
end_path.push_back(m_path.at(k));
453445
}
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+
454464
// Build the string
455465
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);
457467
if (IsRange()) {
458468
out += "/*";
459469
assert(m_derive == DeriveType::UNHARDENED);
@@ -533,19 +543,19 @@ class DescriptorImpl : public Descriptor
533543
return false;
534544
}
535545

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
537547
{
538548
size_t pos = 0;
539549
for (const auto& scriptarg : m_subdescriptor_args) {
540550
if (pos++) ret += ",";
541551
std::string tmp;
542-
if (!scriptarg->ToStringHelper(arg, tmp, type)) return false;
552+
if (!scriptarg->ToStringHelper(arg, tmp, type, cache)) return false;
543553
ret += std::move(tmp);
544554
}
545555
return true;
546556
}
547557

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
549559
{
550560
std::string extra = ToStringExtra();
551561
size_t pos = extra.size() > 0 ? 1 : 0;
@@ -555,7 +565,7 @@ class DescriptorImpl : public Descriptor
555565
std::string tmp;
556566
switch (type) {
557567
case StringType::NORMALIZED:
558-
if (!pubkey->ToNormalizedString(*arg, tmp)) return false;
568+
if (!pubkey->ToNormalizedString(*arg, tmp, cache)) return false;
559569
break;
560570
case StringType::PRIVATE:
561571
if (!pubkey->ToPrivateString(*arg, tmp)) return false;
@@ -567,7 +577,7 @@ class DescriptorImpl : public Descriptor
567577
ret += std::move(tmp);
568578
}
569579
std::string subscript;
570-
if (!ToStringSubScriptHelper(arg, subscript, type)) return false;
580+
if (!ToStringSubScriptHelper(arg, subscript, type, cache)) return false;
571581
if (pos && subscript.size()) ret += ',';
572582
out = std::move(ret) + std::move(subscript) + ")";
573583
return true;
@@ -587,9 +597,9 @@ class DescriptorImpl : public Descriptor
587597
return ret;
588598
}
589599

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
591601
{
592-
bool ret = ToStringHelper(&arg, out, StringType::NORMALIZED);
602+
bool ret = ToStringHelper(&arg, out, StringType::NORMALIZED, cache);
593603
out = AddChecksum(out);
594604
return ret;
595605
}
@@ -843,7 +853,7 @@ class TRDescriptor final : public DescriptorImpl
843853
out.tr_spenddata[output].Merge(builder.GetSpendData());
844854
return Vector(GetScriptForDestination(output));
845855
}
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
847857
{
848858
if (m_depths.empty()) return true;
849859
std::vector<bool> path;
@@ -854,7 +864,7 @@ class TRDescriptor final : public DescriptorImpl
854864
path.push_back(false);
855865
}
856866
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;
858868
ret += std::move(tmp);
859869
while (!path.empty() && path.back()) {
860870
if (path.size() > 1) ret += '}';

src/script/descriptor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ struct Descriptor {
115115
virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0;
116116

117117
/** Convert the descriptor to a normalized string. Normalized descriptors have the xpub at the last hardened step. This fails if the provided provider does not have the private keys to derive that xpub. */
118-
virtual bool ToNormalizedString(const SigningProvider& provider, std::string& out) const = 0;
118+
virtual bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
119119

120120
/** Expand a descriptor at a specified position.
121121
*

src/wallet/scriptpubkeyman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2276,7 +2276,7 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out) const
22762276
FlatSigningProvider provider;
22772277
provider.keys = GetKeys();
22782278

2279-
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out);
2279+
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, &m_wallet_descriptor.cache);
22802280
}
22812281

22822282
void DescriptorScriptPubKeyMan::UpgradeDescriptorCache()

0 commit comments

Comments
 (0)