0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

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.
This commit is contained in:
Andrew Chow 2021-03-01 14:48:59 -05:00
parent 7a26ff10c2
commit 3280704886
3 changed files with 36 additions and 26 deletions

View file

@ -181,7 +181,7 @@ public:
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
/** Get the descriptor string form with the xpub at the last hardened derivation */
virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out) const = 0;
virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
/** Derive a private key, if private data is available in arg. */
virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
@ -216,10 +216,10 @@ public:
ret = "[" + OriginString() + "]" + std::move(sub);
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& ret) const override
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
{
std::string sub;
if (!m_provider->ToNormalizedString(arg, sub)) return false;
if (!m_provider->ToNormalizedString(arg, sub, cache)) return false;
// If m_provider is a BIP32PubkeyProvider, we may get a string formatted like a OriginPubkeyProvider
// In that case, we need to strip out the leading square bracket and fingerprint from the substring,
// and append that to our own origin string.
@ -263,7 +263,7 @@ public:
ret = EncodeSecret(key);
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& ret) const override
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
{
ret = ToString();
return true;
@ -412,7 +412,7 @@ public:
}
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& out) const override
bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
{
// For hardened derivation type, just return the typical string, nothing to normalize
if (m_derive == DeriveType::HARDENED) {
@ -431,29 +431,39 @@ public:
out = ToString();
return true;
}
// Derive the xpub at the last hardened step
CExtKey xprv;
if (!GetExtKey(arg, xprv)) return false;
// Get the path to the last hardened stup
KeyOriginInfo origin;
int k = 0;
for (; k <= i; ++k) {
// Derive
xprv.Derive(xprv, m_path.at(k));
// Add to the path
origin.path.push_back(m_path.at(k));
// First derivation element, get the fingerprint for origin
if (k == 0) {
std::copy(xprv.vchFingerprint, xprv.vchFingerprint + 4, origin.fingerprint);
}
}
// Build the remaining path
KeyPath end_path;
for (; k < (int)m_path.size(); ++k) {
end_path.push_back(m_path.at(k));
}
// Get the fingerprint
CKeyID id = m_root_extkey.pubkey.GetID();
std::copy(id.begin(), id.begin() + 4, origin.fingerprint);
CExtPubKey xpub;
CExtKey lh_xprv;
// If we have the cache, just get the parent xpub
if (cache != nullptr) {
cache->GetCachedLastHardenedExtPubKey(m_expr_index, xpub);
}
if (!xpub.pubkey.IsValid()) {
// Cache miss, or nor cache, or need privkey
CExtKey xprv;
if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return false;
xpub = lh_xprv.Neuter();
}
assert(xpub.pubkey.IsValid());
// Build the string
std::string origin_str = HexStr(origin.fingerprint) + FormatHDKeypath(origin.path);
out = "[" + origin_str + "]" + EncodeExtPubKey(xprv.Neuter()) + FormatHDKeypath(end_path);
out = "[" + origin_str + "]" + EncodeExtPubKey(xpub) + FormatHDKeypath(end_path);
if (IsRange()) {
out += "/*";
assert(m_derive == DeriveType::UNHARDENED);
@ -533,19 +543,19 @@ public:
return false;
}
virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type) const
virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const
{
size_t pos = 0;
for (const auto& scriptarg : m_subdescriptor_args) {
if (pos++) ret += ",";
std::string tmp;
if (!scriptarg->ToStringHelper(arg, tmp, type)) return false;
if (!scriptarg->ToStringHelper(arg, tmp, type, cache)) return false;
ret += std::move(tmp);
}
return true;
}
bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type) const
bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr) const
{
std::string extra = ToStringExtra();
size_t pos = extra.size() > 0 ? 1 : 0;
@ -555,7 +565,7 @@ public:
std::string tmp;
switch (type) {
case StringType::NORMALIZED:
if (!pubkey->ToNormalizedString(*arg, tmp)) return false;
if (!pubkey->ToNormalizedString(*arg, tmp, cache)) return false;
break;
case StringType::PRIVATE:
if (!pubkey->ToPrivateString(*arg, tmp)) return false;
@ -567,7 +577,7 @@ public:
ret += std::move(tmp);
}
std::string subscript;
if (!ToStringSubScriptHelper(arg, subscript, type)) return false;
if (!ToStringSubScriptHelper(arg, subscript, type, cache)) return false;
if (pos && subscript.size()) ret += ',';
out = std::move(ret) + std::move(subscript) + ")";
return true;
@ -587,9 +597,9 @@ public:
return ret;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& out) const override final
bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override final
{
bool ret = ToStringHelper(&arg, out, StringType::NORMALIZED);
bool ret = ToStringHelper(&arg, out, StringType::NORMALIZED, cache);
out = AddChecksum(out);
return ret;
}
@ -843,7 +853,7 @@ protected:
out.tr_spenddata[output].Merge(builder.GetSpendData());
return Vector(GetScriptForDestination(output));
}
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type) const override
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
{
if (m_depths.empty()) return true;
std::vector<bool> path;
@ -854,7 +864,7 @@ protected:
path.push_back(false);
}
std::string tmp;
if (!m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, type)) return false;
if (!m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, type, cache)) return false;
ret += std::move(tmp);
while (!path.empty() && path.back()) {
if (path.size() > 1) ret += '}';

View file

@ -115,7 +115,7 @@ struct Descriptor {
virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0;
/** 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. */
virtual bool ToNormalizedString(const SigningProvider& provider, std::string& out) const = 0;
virtual bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
/** Expand a descriptor at a specified position.
*

View file

@ -2276,7 +2276,7 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out) const
FlatSigningProvider provider;
provider.keys = GetKeys();
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out);
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, &m_wallet_descriptor.cache);
}
void DescriptorScriptPubKeyMan::UpgradeDescriptorCache()