mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
Merge bitcoin/bitcoin#31243: descriptor: Move filling of keys from DescriptorImpl::MakeScripts
to PubkeyProvider::GetPubKey
acee5c59e6
descriptors: Have GetPrivKey fill keys directly (Ava Chow)4b0303197e
descriptors: Move FlatSigningProvider pubkey filling to GetPubKey (Ava Chow)25a3b9b0f5
descriptors: Have GetPubKey fill origins directly (Ava Chow)6268bde0af
descriptor: Remove unused parent_info from BIP32PUbKeyProvider::GetPubKey (Ava Chow)0ff072caa1
wallet, rpc: Only allow keypool import from single key descriptors (Ava Chow) Pull request description: Instead of having `MakeScripts` infer what pubkeys need to go into the output `FlatSigningProvider`, have each of the `PubkeyProviders` that have `GetPubKey` and `GetPrivKey` called fill it directly with relevant keys and origins. This allows for keys and origins to be added that won't directly appear in the output, which is necessary for `musig()` descriptors. Split from #29675 ACKs for top commit: fjahr: Code review ACKacee5c59e6
theStack: re-ACKacee5c59e6
rkrux: ACKacee5c5
Tree-SHA512: c1841359bcb08cdd433122deef96579236928660785f3357a3eb584e47d290cd1c60ebe8f7fba50f178ba45c9a90773124e0f509e36c5a0df97c1a4890e03e5c
This commit is contained in:
commit
3e78ac6811
4 changed files with 94 additions and 75 deletions
|
@ -174,22 +174,20 @@ public:
|
||||||
* Used by the Miniscript descriptors to check for duplicate keys in the script.
|
* Used by the Miniscript descriptors to check for duplicate keys in the script.
|
||||||
*/
|
*/
|
||||||
bool operator<(PubkeyProvider& other) const {
|
bool operator<(PubkeyProvider& other) const {
|
||||||
CPubKey a, b;
|
FlatSigningProvider dummy;
|
||||||
SigningProvider dummy;
|
|
||||||
KeyOriginInfo dummy_info;
|
|
||||||
|
|
||||||
GetPubKey(0, dummy, a, dummy_info);
|
std::optional<CPubKey> a = GetPubKey(0, dummy, dummy);
|
||||||
other.GetPubKey(0, dummy, b, dummy_info);
|
std::optional<CPubKey> b = other.GetPubKey(0, dummy, dummy);
|
||||||
|
|
||||||
return a < b;
|
return a < b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Derive a public key.
|
/** Derive a public key and put it into out.
|
||||||
* read_cache is the cache to read keys from (if not nullptr)
|
* read_cache is the cache to read keys from (if not nullptr)
|
||||||
* write_cache is the cache to write keys to (if not nullptr)
|
* write_cache is the cache to write keys to (if not nullptr)
|
||||||
* Caches are not exclusive but this is not tested. Currently we use them exclusively
|
* Caches are not exclusive but this is not tested. Currently we use them exclusively
|
||||||
*/
|
*/
|
||||||
virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
|
virtual std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
|
||||||
|
|
||||||
/** Whether this represent multiple public keys at different positions. */
|
/** Whether this represent multiple public keys at different positions. */
|
||||||
virtual bool IsRange() const = 0;
|
virtual bool IsRange() const = 0;
|
||||||
|
@ -213,8 +211,8 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) 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. */
|
/** Derive a private key, if private data is available in arg and put it into out. */
|
||||||
virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
|
virtual void GetPrivKey(int pos, const SigningProvider& arg, FlatSigningProvider& out) const = 0;
|
||||||
|
|
||||||
/** Return the non-extended public key for this PubkeyProvider, if it has one. */
|
/** Return the non-extended public key for this PubkeyProvider, if it has one. */
|
||||||
virtual std::optional<CPubKey> GetRootPubKey() const = 0;
|
virtual std::optional<CPubKey> GetRootPubKey() const = 0;
|
||||||
|
@ -240,12 +238,16 @@ class OriginPubkeyProvider final : public PubkeyProvider
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider, bool apostrophe) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)), m_apostrophe(apostrophe) {}
|
OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider, bool apostrophe) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)), m_apostrophe(apostrophe) {}
|
||||||
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
||||||
{
|
{
|
||||||
if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
|
std::optional<CPubKey> pub = m_provider->GetPubKey(pos, arg, out, read_cache, write_cache);
|
||||||
std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
|
if (!pub) return std::nullopt;
|
||||||
info.path.insert(info.path.begin(), m_origin.path.begin(), m_origin.path.end());
|
Assert(out.pubkeys.contains(pub->GetID()));
|
||||||
return true;
|
auto& [pubkey, suborigin] = out.origins[pub->GetID()];
|
||||||
|
Assert(pubkey == *pub); // m_provider must have a valid origin by this point.
|
||||||
|
std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), suborigin.fingerprint);
|
||||||
|
suborigin.path.insert(suborigin.path.begin(), m_origin.path.begin(), m_origin.path.end());
|
||||||
|
return pub;
|
||||||
}
|
}
|
||||||
bool IsRange() const override { return m_provider->IsRange(); }
|
bool IsRange() const override { return m_provider->IsRange(); }
|
||||||
size_t GetSize() const override { return m_provider->GetSize(); }
|
size_t GetSize() const override { return m_provider->GetSize(); }
|
||||||
|
@ -272,9 +274,9 @@ public:
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
|
void GetPrivKey(int pos, const SigningProvider& arg, FlatSigningProvider& out) const override
|
||||||
{
|
{
|
||||||
return m_provider->GetPrivKey(pos, arg, key);
|
m_provider->GetPrivKey(pos, arg, out);
|
||||||
}
|
}
|
||||||
std::optional<CPubKey> GetRootPubKey() const override
|
std::optional<CPubKey> GetRootPubKey() const override
|
||||||
{
|
{
|
||||||
|
@ -296,24 +298,33 @@ class ConstPubkeyProvider final : public PubkeyProvider
|
||||||
CPubKey m_pubkey;
|
CPubKey m_pubkey;
|
||||||
bool m_xonly;
|
bool m_xonly;
|
||||||
|
|
||||||
|
std::optional<CKey> GetPrivKey(const SigningProvider& arg) const
|
||||||
|
{
|
||||||
|
CKey key;
|
||||||
|
if (!(m_xonly ? arg.GetKeyByXOnly(XOnlyPubKey(m_pubkey), key) :
|
||||||
|
arg.GetKey(m_pubkey.GetID(), key))) return std::nullopt;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
|
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
|
||||||
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider&, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
||||||
{
|
{
|
||||||
key = m_pubkey;
|
KeyOriginInfo info;
|
||||||
info.path.clear();
|
|
||||||
CKeyID keyid = m_pubkey.GetID();
|
CKeyID keyid = m_pubkey.GetID();
|
||||||
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
|
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
|
||||||
return true;
|
out.origins.emplace(keyid, std::make_pair(m_pubkey, info));
|
||||||
|
out.pubkeys.emplace(keyid, m_pubkey);
|
||||||
|
return m_pubkey;
|
||||||
}
|
}
|
||||||
bool IsRange() const override { return false; }
|
bool IsRange() const override { return false; }
|
||||||
size_t GetSize() const override { return m_pubkey.size(); }
|
size_t GetSize() const override { return m_pubkey.size(); }
|
||||||
std::string ToString(StringType type) const override { return m_xonly ? HexStr(m_pubkey).substr(2) : HexStr(m_pubkey); }
|
std::string ToString(StringType type) const override { return m_xonly ? HexStr(m_pubkey).substr(2) : HexStr(m_pubkey); }
|
||||||
bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
|
bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
|
||||||
{
|
{
|
||||||
CKey key;
|
std::optional<CKey> key = GetPrivKey(arg);
|
||||||
if (!GetPrivKey(/*pos=*/0, arg, key)) return false;
|
if (!key) return false;
|
||||||
ret = EncodeSecret(key);
|
ret = EncodeSecret(*key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
|
bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
|
||||||
|
@ -321,10 +332,11 @@ public:
|
||||||
ret = ToString(StringType::PUBLIC);
|
ret = ToString(StringType::PUBLIC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
|
void GetPrivKey(int pos, const SigningProvider& arg, FlatSigningProvider& out) const override
|
||||||
{
|
{
|
||||||
return m_xonly ? arg.GetKeyByXOnly(XOnlyPubKey(m_pubkey), key) :
|
std::optional<CKey> key = GetPrivKey(arg);
|
||||||
arg.GetKey(m_pubkey.GetID(), key);
|
if (!key) return;
|
||||||
|
out.keys.emplace(key->GetPubKey().GetID(), *key);
|
||||||
}
|
}
|
||||||
std::optional<CPubKey> GetRootPubKey() const override
|
std::optional<CPubKey> GetRootPubKey() const override
|
||||||
{
|
{
|
||||||
|
@ -394,18 +406,14 @@ public:
|
||||||
BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive, bool apostrophe) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive), m_apostrophe(apostrophe) {}
|
BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive, bool apostrophe) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive), m_apostrophe(apostrophe) {}
|
||||||
bool IsRange() const override { return m_derive != DeriveType::NO; }
|
bool IsRange() const override { return m_derive != DeriveType::NO; }
|
||||||
size_t GetSize() const override { return 33; }
|
size_t GetSize() const override { return 33; }
|
||||||
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
|
||||||
{
|
{
|
||||||
// Info of parent of the to be derived pubkey
|
KeyOriginInfo info;
|
||||||
KeyOriginInfo parent_info;
|
|
||||||
CKeyID keyid = m_root_extkey.pubkey.GetID();
|
CKeyID keyid = m_root_extkey.pubkey.GetID();
|
||||||
std::copy(keyid.begin(), keyid.begin() + sizeof(parent_info.fingerprint), parent_info.fingerprint);
|
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
|
||||||
parent_info.path = m_path;
|
info.path = m_path;
|
||||||
|
if (m_derive == DeriveType::UNHARDENED) info.path.push_back((uint32_t)pos);
|
||||||
// Info of the derived key itself which is copied out upon successful completion
|
if (m_derive == DeriveType::HARDENED) info.path.push_back(((uint32_t)pos) | 0x80000000L);
|
||||||
KeyOriginInfo final_info_out_tmp = parent_info;
|
|
||||||
if (m_derive == DeriveType::UNHARDENED) final_info_out_tmp.path.push_back((uint32_t)pos);
|
|
||||||
if (m_derive == DeriveType::HARDENED) final_info_out_tmp.path.push_back(((uint32_t)pos) | 0x80000000L);
|
|
||||||
|
|
||||||
// Derive keys or fetch them from cache
|
// Derive keys or fetch them from cache
|
||||||
CExtPubKey final_extkey = m_root_extkey;
|
CExtPubKey final_extkey = m_root_extkey;
|
||||||
|
@ -414,16 +422,16 @@ public:
|
||||||
bool der = true;
|
bool der = true;
|
||||||
if (read_cache) {
|
if (read_cache) {
|
||||||
if (!read_cache->GetCachedDerivedExtPubKey(m_expr_index, pos, final_extkey)) {
|
if (!read_cache->GetCachedDerivedExtPubKey(m_expr_index, pos, final_extkey)) {
|
||||||
if (m_derive == DeriveType::HARDENED) return false;
|
if (m_derive == DeriveType::HARDENED) return std::nullopt;
|
||||||
// Try to get the derivation parent
|
// Try to get the derivation parent
|
||||||
if (!read_cache->GetCachedParentExtPubKey(m_expr_index, parent_extkey)) return false;
|
if (!read_cache->GetCachedParentExtPubKey(m_expr_index, parent_extkey)) return std::nullopt;
|
||||||
final_extkey = parent_extkey;
|
final_extkey = parent_extkey;
|
||||||
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
|
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
|
||||||
}
|
}
|
||||||
} else if (IsHardened()) {
|
} else if (IsHardened()) {
|
||||||
CExtKey xprv;
|
CExtKey xprv;
|
||||||
CExtKey lh_xprv;
|
CExtKey lh_xprv;
|
||||||
if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return false;
|
if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return std::nullopt;
|
||||||
parent_extkey = xprv.Neuter();
|
parent_extkey = xprv.Neuter();
|
||||||
if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive(xprv, pos);
|
if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive(xprv, pos);
|
||||||
if (m_derive == DeriveType::HARDENED) der = xprv.Derive(xprv, pos | 0x80000000UL);
|
if (m_derive == DeriveType::HARDENED) der = xprv.Derive(xprv, pos | 0x80000000UL);
|
||||||
|
@ -433,16 +441,16 @@ public:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto entry : m_path) {
|
for (auto entry : m_path) {
|
||||||
if (!parent_extkey.Derive(parent_extkey, entry)) return false;
|
if (!parent_extkey.Derive(parent_extkey, entry)) return std::nullopt;
|
||||||
}
|
}
|
||||||
final_extkey = parent_extkey;
|
final_extkey = parent_extkey;
|
||||||
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
|
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
|
||||||
assert(m_derive != DeriveType::HARDENED);
|
assert(m_derive != DeriveType::HARDENED);
|
||||||
}
|
}
|
||||||
if (!der) return false;
|
if (!der) return std::nullopt;
|
||||||
|
|
||||||
final_info_out = final_info_out_tmp;
|
out.origins.emplace(final_extkey.pubkey.GetID(), std::make_pair(final_extkey.pubkey, info));
|
||||||
key_out = final_extkey.pubkey;
|
out.pubkeys.emplace(final_extkey.pubkey.GetID(), final_extkey.pubkey);
|
||||||
|
|
||||||
if (write_cache) {
|
if (write_cache) {
|
||||||
// Only cache parent if there is any unhardened derivation
|
// Only cache parent if there is any unhardened derivation
|
||||||
|
@ -452,12 +460,12 @@ public:
|
||||||
if (last_hardened_extkey.pubkey.IsValid()) {
|
if (last_hardened_extkey.pubkey.IsValid()) {
|
||||||
write_cache->CacheLastHardenedExtPubKey(m_expr_index, last_hardened_extkey);
|
write_cache->CacheLastHardenedExtPubKey(m_expr_index, last_hardened_extkey);
|
||||||
}
|
}
|
||||||
} else if (final_info_out.path.size() > 0) {
|
} else if (info.path.size() > 0) {
|
||||||
write_cache->CacheDerivedExtPubKey(m_expr_index, pos, final_extkey);
|
write_cache->CacheDerivedExtPubKey(m_expr_index, pos, final_extkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return final_extkey.pubkey;
|
||||||
}
|
}
|
||||||
std::string ToString(StringType type, bool normalized) const
|
std::string ToString(StringType type, bool normalized) const
|
||||||
{
|
{
|
||||||
|
@ -543,15 +551,14 @@ public:
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
|
void GetPrivKey(int pos, const SigningProvider& arg, FlatSigningProvider& out) const override
|
||||||
{
|
{
|
||||||
CExtKey extkey;
|
CExtKey extkey;
|
||||||
CExtKey dummy;
|
CExtKey dummy;
|
||||||
if (!GetDerivedExtKey(arg, extkey, dummy)) return false;
|
if (!GetDerivedExtKey(arg, extkey, dummy)) return;
|
||||||
if (m_derive == DeriveType::UNHARDENED && !extkey.Derive(extkey, pos)) return false;
|
if (m_derive == DeriveType::UNHARDENED && !extkey.Derive(extkey, pos)) return;
|
||||||
if (m_derive == DeriveType::HARDENED && !extkey.Derive(extkey, pos | 0x80000000UL)) return false;
|
if (m_derive == DeriveType::HARDENED && !extkey.Derive(extkey, pos | 0x80000000UL)) return;
|
||||||
key = extkey.key;
|
out.keys.emplace(extkey.key.GetPubKey().GetID(), extkey.key);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
std::optional<CPubKey> GetRootPubKey() const override
|
std::optional<CPubKey> GetRootPubKey() const override
|
||||||
{
|
{
|
||||||
|
@ -700,16 +707,17 @@ public:
|
||||||
// NOLINTNEXTLINE(misc-no-recursion)
|
// NOLINTNEXTLINE(misc-no-recursion)
|
||||||
bool ExpandHelper(int pos, const SigningProvider& arg, const DescriptorCache* read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache) const
|
bool ExpandHelper(int pos, const SigningProvider& arg, const DescriptorCache* read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache) const
|
||||||
{
|
{
|
||||||
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
|
FlatSigningProvider subprovider;
|
||||||
entries.reserve(m_pubkey_args.size());
|
std::vector<CPubKey> pubkeys;
|
||||||
|
pubkeys.reserve(m_pubkey_args.size());
|
||||||
|
|
||||||
// Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
|
// Construct temporary data in `pubkeys`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
|
||||||
for (const auto& p : m_pubkey_args) {
|
for (const auto& p : m_pubkey_args) {
|
||||||
entries.emplace_back();
|
std::optional<CPubKey> pubkey = p->GetPubKey(pos, arg, subprovider, read_cache, write_cache);
|
||||||
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
|
if (!pubkey) return false;
|
||||||
|
pubkeys.push_back(pubkey.value());
|
||||||
}
|
}
|
||||||
std::vector<CScript> subscripts;
|
std::vector<CScript> subscripts;
|
||||||
FlatSigningProvider subprovider;
|
|
||||||
for (const auto& subarg : m_subdescriptor_args) {
|
for (const auto& subarg : m_subdescriptor_args) {
|
||||||
std::vector<CScript> outscripts;
|
std::vector<CScript> outscripts;
|
||||||
if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
|
if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
|
||||||
|
@ -718,13 +726,6 @@ public:
|
||||||
}
|
}
|
||||||
out.Merge(std::move(subprovider));
|
out.Merge(std::move(subprovider));
|
||||||
|
|
||||||
std::vector<CPubKey> pubkeys;
|
|
||||||
pubkeys.reserve(entries.size());
|
|
||||||
for (auto& entry : entries) {
|
|
||||||
pubkeys.push_back(entry.first);
|
|
||||||
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
|
|
||||||
}
|
|
||||||
|
|
||||||
output_scripts = MakeScripts(pubkeys, std::span{subscripts}, out);
|
output_scripts = MakeScripts(pubkeys, std::span{subscripts}, out);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -743,9 +744,7 @@ public:
|
||||||
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
|
void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
|
||||||
{
|
{
|
||||||
for (const auto& p : m_pubkey_args) {
|
for (const auto& p : m_pubkey_args) {
|
||||||
CKey key;
|
p->GetPrivKey(pos, provider, out);
|
||||||
if (!p->GetPrivKey(pos, provider, key)) continue;
|
|
||||||
out.keys.emplace(key.GetPubKey().GetID(), key);
|
|
||||||
}
|
}
|
||||||
for (const auto& arg : m_subdescriptor_args) {
|
for (const auto& arg : m_subdescriptor_args) {
|
||||||
arg->ExpandPrivate(pos, provider, out);
|
arg->ExpandPrivate(pos, provider, out);
|
||||||
|
@ -800,6 +799,7 @@ public:
|
||||||
return OutputTypeFromDestination(m_destination);
|
return OutputTypeFromDestination(m_destination);
|
||||||
}
|
}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return GetScriptForDestination(m_destination).size(); }
|
std::optional<int64_t> ScriptSize() const override { return GetScriptForDestination(m_destination).size(); }
|
||||||
|
@ -827,6 +827,7 @@ public:
|
||||||
return OutputTypeFromDestination(dest);
|
return OutputTypeFromDestination(dest);
|
||||||
}
|
}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return m_script.size(); }
|
std::optional<int64_t> ScriptSize() const override { return m_script.size(); }
|
||||||
|
@ -855,6 +856,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {}
|
PKDescriptor(std::unique_ptr<PubkeyProvider> prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return true; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override {
|
std::optional<int64_t> ScriptSize() const override {
|
||||||
return 1 + (m_xonly ? 32 : m_pubkey_args[0]->GetSize()) + 1;
|
return 1 + (m_xonly ? 32 : m_pubkey_args[0]->GetSize()) + 1;
|
||||||
|
@ -881,16 +883,16 @@ public:
|
||||||
class PKHDescriptor final : public DescriptorImpl
|
class PKHDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript>, FlatSigningProvider& out) const override
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript>, FlatSigningProvider&) const override
|
||||||
{
|
{
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
|
||||||
return Vector(GetScriptForDestination(PKHash(id)));
|
return Vector(GetScriptForDestination(PKHash(id)));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
|
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
|
||||||
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
|
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return true; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 1 + 20 + 1 + 1; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 1 + 20 + 1 + 1; }
|
||||||
|
|
||||||
|
@ -915,16 +917,16 @@ public:
|
||||||
class WPKHDescriptor final : public DescriptorImpl
|
class WPKHDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript>, FlatSigningProvider& out) const override
|
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript>, FlatSigningProvider&) const override
|
||||||
{
|
{
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
|
||||||
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
|
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
|
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
|
||||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return true; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20; }
|
||||||
|
|
||||||
|
@ -953,7 +955,6 @@ protected:
|
||||||
{
|
{
|
||||||
std::vector<CScript> ret;
|
std::vector<CScript> ret;
|
||||||
CKeyID id = keys[0].GetID();
|
CKeyID id = keys[0].GetID();
|
||||||
out.pubkeys.emplace(id, keys[0]);
|
|
||||||
ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK
|
ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK
|
||||||
ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH
|
ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH
|
||||||
if (keys[0].IsCompressed()) {
|
if (keys[0].IsCompressed()) {
|
||||||
|
@ -967,6 +968,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
|
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
|
||||||
bool IsSingleType() const final { return false; }
|
bool IsSingleType() const final { return false; }
|
||||||
|
bool IsSingleKey() const final { return true; }
|
||||||
std::unique_ptr<DescriptorImpl> Clone() const override
|
std::unique_ptr<DescriptorImpl> Clone() const override
|
||||||
{
|
{
|
||||||
return std::make_unique<ComboDescriptor>(m_pubkey_args.at(0)->Clone());
|
return std::make_unique<ComboDescriptor>(m_pubkey_args.at(0)->Clone());
|
||||||
|
@ -991,6 +993,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
|
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override {
|
std::optional<int64_t> ScriptSize() const override {
|
||||||
const auto n_keys = m_pubkey_args.size();
|
const auto n_keys = m_pubkey_args.size();
|
||||||
|
@ -1042,6 +1045,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
MultiADescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti_a" : "multi_a"), m_threshold(threshold), m_sorted(sorted) {}
|
MultiADescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti_a" : "multi_a"), m_threshold(threshold), m_sorted(sorted) {}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override {
|
std::optional<int64_t> ScriptSize() const override {
|
||||||
const auto n_keys = m_pubkey_args.size();
|
const auto n_keys = m_pubkey_args.size();
|
||||||
|
@ -1088,6 +1092,7 @@ public:
|
||||||
return OutputType::LEGACY;
|
return OutputType::LEGACY;
|
||||||
}
|
}
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return m_subdescriptor_args[0]->IsSingleKey(); }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20 + 1; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20 + 1; }
|
||||||
|
|
||||||
|
@ -1129,6 +1134,7 @@ public:
|
||||||
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
|
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
|
||||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return m_subdescriptor_args[0]->IsSingleKey(); }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||||
|
|
||||||
|
@ -1175,7 +1181,6 @@ protected:
|
||||||
builder.Finalize(xpk);
|
builder.Finalize(xpk);
|
||||||
WitnessV1Taproot output = builder.GetOutput();
|
WitnessV1Taproot output = builder.GetOutput();
|
||||||
out.tr_trees[output] = builder;
|
out.tr_trees[output] = builder;
|
||||||
out.pubkeys.emplace(keys[0].GetID(), keys[0]);
|
|
||||||
return Vector(GetScriptForDestination(output));
|
return Vector(GetScriptForDestination(output));
|
||||||
}
|
}
|
||||||
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
|
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
|
||||||
|
@ -1207,6 +1212,7 @@ public:
|
||||||
}
|
}
|
||||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||||
|
|
||||||
|
@ -1334,6 +1340,7 @@ public:
|
||||||
|
|
||||||
bool IsSolvable() const override { return true; }
|
bool IsSolvable() const override { return true; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return m_node->ScriptSize(); }
|
std::optional<int64_t> ScriptSize() const override { return m_node->ScriptSize(); }
|
||||||
|
|
||||||
|
@ -1373,6 +1380,7 @@ public:
|
||||||
RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}
|
RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}
|
||||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
||||||
bool IsSingleType() const final { return true; }
|
bool IsSingleType() const final { return true; }
|
||||||
|
bool IsSingleKey() const final { return false; }
|
||||||
|
|
||||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,11 @@ struct Descriptor {
|
||||||
/** Whether this descriptor will return one scriptPubKey or multiple (aka is or is not combo) */
|
/** Whether this descriptor will return one scriptPubKey or multiple (aka is or is not combo) */
|
||||||
virtual bool IsSingleType() const = 0;
|
virtual bool IsSingleType() const = 0;
|
||||||
|
|
||||||
|
/** Whether this descriptor only produces single key scripts (i.e. pk(), pkh(), wpkh(), sh() and wsh() nested of those, and combo())
|
||||||
|
* TODO: Remove this method once legacy wallets are removed as it is only necessary for importmulti.
|
||||||
|
*/
|
||||||
|
virtual bool IsSingleKey() const = 0;
|
||||||
|
|
||||||
/** Convert the descriptor to a private string. This fails if the provided provider does not have the relevant private keys. */
|
/** Convert the descriptor to a private string. This fails if the provided provider does not have the relevant private keys. */
|
||||||
virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0;
|
virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -1091,6 +1091,9 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||||
std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
|
std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only single key descriptors are allowed to be imported to a legacy wallet's keypool
|
||||||
|
bool can_keypool = parsed_descs.at(0)->IsSingleKey();
|
||||||
|
|
||||||
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
|
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
|
||||||
|
|
||||||
for (size_t j = 0; j < parsed_descs.size(); ++j) {
|
for (size_t j = 0; j < parsed_descs.size(); ++j) {
|
||||||
|
@ -1107,8 +1110,10 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||||
std::vector<CScript> scripts_temp;
|
std::vector<CScript> scripts_temp;
|
||||||
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
||||||
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
||||||
for (const auto& key_pair : out_keys.pubkeys) {
|
if (can_keypool) {
|
||||||
ordered_pubkeys.emplace_back(key_pair.first, desc_internal);
|
for (const auto& key_pair : out_keys.pubkeys) {
|
||||||
|
ordered_pubkeys.emplace_back(key_pair.first, desc_internal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& x : out_keys.scripts) {
|
for (const auto& x : out_keys.scripts) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
bool IsRange() const override { return false; }
|
bool IsRange() const override { return false; }
|
||||||
bool IsSolvable() const override { return false; }
|
bool IsSolvable() const override { return false; }
|
||||||
bool IsSingleType() const override { return true; }
|
bool IsSingleType() const override { return true; }
|
||||||
|
bool IsSingleKey() const override { return true; }
|
||||||
bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; }
|
bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; }
|
||||||
bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; }
|
bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; }
|
||||||
bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; };
|
bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; };
|
||||||
|
|
Loading…
Add table
Reference in a new issue