Skip to content

Commit 070e746

Browse files
committed
descriptors: Have GetPubKey fill origins directly
Instead of having ExpandHelper fill in the origins in the FlatSigningProvider output, have GetPubKey do it by itself. This reduces the extra variables needed in order to track and set origins in ExpandHelper. Also changes GetPubKey to return a std::optional<CPubKey> rather than using a bool and output parameters.
1 parent 6a31eb5 commit 070e746

File tree

1 file changed

+38
-45
lines changed

1 file changed

+38
-45
lines changed

src/script/descriptor.cpp

+38-45
Original file line numberDiff line numberDiff line change
@@ -174,22 +174,20 @@ struct PubkeyProvider
174174
* Used by the Miniscript descriptors to check for duplicate keys in the script.
175175
*/
176176
bool operator<(PubkeyProvider& other) const {
177-
CPubKey a, b;
178-
SigningProvider dummy;
179-
KeyOriginInfo dummy_info;
177+
FlatSigningProvider dummy;
180178

181-
GetPubKey(0, dummy, a, dummy_info);
182-
other.GetPubKey(0, dummy, b, dummy_info);
179+
std::optional<CPubKey> a = GetPubKey(0, dummy, dummy);
180+
std::optional<CPubKey> b = other.GetPubKey(0, dummy, dummy);
183181

184182
return a < b;
185183
}
186184

187-
/** Derive a public key.
185+
/** Derive a public key and put it into out.
188186
* read_cache is the cache to read keys from (if not nullptr)
189187
* write_cache is the cache to write keys to (if not nullptr)
190188
* Caches are not exclusive but this is not tested. Currently we use them exclusively
191189
*/
192-
virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
190+
virtual std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
193191

194192
/** Whether this represent multiple public keys at different positions. */
195193
virtual bool IsRange() const = 0;
@@ -240,12 +238,15 @@ class OriginPubkeyProvider final : public PubkeyProvider
240238

241239
public:
242240
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) {}
243-
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
241+
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
244242
{
245-
if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
246-
std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
247-
info.path.insert(info.path.begin(), m_origin.path.begin(), m_origin.path.end());
248-
return true;
243+
std::optional<CPubKey> pub = m_provider->GetPubKey(pos, arg, out, read_cache, write_cache);
244+
if (!pub) return std::nullopt;
245+
auto& [pubkey, suborigin] = out.origins[pub->GetID()];
246+
Assert(pubkey == *pub); // All subproviders must be inserting a valid origin already
247+
std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), suborigin.fingerprint);
248+
suborigin.path.insert(suborigin.path.begin(), m_origin.path.begin(), m_origin.path.end());
249+
return pub;
249250
}
250251
bool IsRange() const override { return m_provider->IsRange(); }
251252
size_t GetSize() const override { return m_provider->GetSize(); }
@@ -298,13 +299,13 @@ class ConstPubkeyProvider final : public PubkeyProvider
298299

299300
public:
300301
ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
301-
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
302+
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
302303
{
303-
key = m_pubkey;
304-
info.path.clear();
304+
KeyOriginInfo info;
305305
CKeyID keyid = m_pubkey.GetID();
306306
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
307-
return true;
307+
out.origins.emplace(keyid, std::make_pair(m_pubkey, info));
308+
return m_pubkey;
308309
}
309310
bool IsRange() const override { return false; }
310311
size_t GetSize() const override { return m_pubkey.size(); }
@@ -394,18 +395,17 @@ class BIP32PubkeyProvider final : public PubkeyProvider
394395
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) {}
395396
bool IsRange() const override { return m_derive != DeriveType::NO; }
396397
size_t GetSize() const override { return 33; }
397-
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
398+
std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
398399
{
399400
// Info of parent of the to be derived pubkey
400-
KeyOriginInfo parent_info;
401+
KeyOriginInfo info;
401402
CKeyID keyid = m_root_extkey.pubkey.GetID();
402-
std::copy(keyid.begin(), keyid.begin() + sizeof(parent_info.fingerprint), parent_info.fingerprint);
403-
parent_info.path = m_path;
403+
std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
404+
info.path = m_path;
404405

405406
// Info of the derived key itself which is copied out upon successful completion
406-
KeyOriginInfo final_info_out_tmp = parent_info;
407-
if (m_derive == DeriveType::UNHARDENED) final_info_out_tmp.path.push_back((uint32_t)pos);
408-
if (m_derive == DeriveType::HARDENED) final_info_out_tmp.path.push_back(((uint32_t)pos) | 0x80000000L);
407+
if (m_derive == DeriveType::UNHARDENED) info.path.push_back((uint32_t)pos);
408+
if (m_derive == DeriveType::HARDENED) info.path.push_back(((uint32_t)pos) | 0x80000000L);
409409

410410
// Derive keys or fetch them from cache
411411
CExtPubKey final_extkey = m_root_extkey;
@@ -414,16 +414,16 @@ class BIP32PubkeyProvider final : public PubkeyProvider
414414
bool der = true;
415415
if (read_cache) {
416416
if (!read_cache->GetCachedDerivedExtPubKey(m_expr_index, pos, final_extkey)) {
417-
if (m_derive == DeriveType::HARDENED) return false;
417+
if (m_derive == DeriveType::HARDENED) return std::nullopt;
418418
// Try to get the derivation parent
419-
if (!read_cache->GetCachedParentExtPubKey(m_expr_index, parent_extkey)) return false;
419+
if (!read_cache->GetCachedParentExtPubKey(m_expr_index, parent_extkey)) return std::nullopt;
420420
final_extkey = parent_extkey;
421421
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
422422
}
423423
} else if (IsHardened()) {
424424
CExtKey xprv;
425425
CExtKey lh_xprv;
426-
if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return false;
426+
if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return std::nullopt;
427427
parent_extkey = xprv.Neuter();
428428
if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive(xprv, pos);
429429
if (m_derive == DeriveType::HARDENED) der = xprv.Derive(xprv, pos | 0x80000000UL);
@@ -433,16 +433,15 @@ class BIP32PubkeyProvider final : public PubkeyProvider
433433
}
434434
} else {
435435
for (auto entry : m_path) {
436-
if (!parent_extkey.Derive(parent_extkey, entry)) return false;
436+
if (!parent_extkey.Derive(parent_extkey, entry)) return std::nullopt;
437437
}
438438
final_extkey = parent_extkey;
439439
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
440440
assert(m_derive != DeriveType::HARDENED);
441441
}
442-
if (!der) return false;
442+
if (!der) return std::nullopt;
443443

444-
final_info_out = final_info_out_tmp;
445-
key_out = final_extkey.pubkey;
444+
out.origins.emplace(final_extkey.pubkey.GetID(), std::make_pair(final_extkey.pubkey, info));
446445

447446
if (write_cache) {
448447
// Only cache parent if there is any unhardened derivation
@@ -452,12 +451,12 @@ class BIP32PubkeyProvider final : public PubkeyProvider
452451
if (last_hardened_extkey.pubkey.IsValid()) {
453452
write_cache->CacheLastHardenedExtPubKey(m_expr_index, last_hardened_extkey);
454453
}
455-
} else if (final_info_out.path.size() > 0) {
454+
} else if (info.path.size() > 0) {
456455
write_cache->CacheDerivedExtPubKey(m_expr_index, pos, final_extkey);
457456
}
458457
}
459458

460-
return true;
459+
return final_extkey.pubkey;
461460
}
462461
std::string ToString(StringType type, bool normalized) const
463462
{
@@ -700,16 +699,17 @@ class DescriptorImpl : public Descriptor
700699
// NOLINTNEXTLINE(misc-no-recursion)
701700
bool ExpandHelper(int pos, const SigningProvider& arg, const DescriptorCache* read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache) const
702701
{
703-
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
704-
entries.reserve(m_pubkey_args.size());
702+
FlatSigningProvider subprovider;
703+
std::vector<CPubKey> pubkeys;
704+
pubkeys.reserve(m_pubkey_args.size());
705705

706-
// Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
706+
// Construct temporary data in `pubkeys`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
707707
for (const auto& p : m_pubkey_args) {
708-
entries.emplace_back();
709-
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
708+
std::optional<CPubKey> pubkey = p->GetPubKey(pos, arg, subprovider, read_cache, write_cache);
709+
if (!pubkey) return false;
710+
pubkeys.push_back(pubkey.value());
710711
}
711712
std::vector<CScript> subscripts;
712-
FlatSigningProvider subprovider;
713713
for (const auto& subarg : m_subdescriptor_args) {
714714
std::vector<CScript> outscripts;
715715
if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
@@ -718,13 +718,6 @@ class DescriptorImpl : public Descriptor
718718
}
719719
out.Merge(std::move(subprovider));
720720

721-
std::vector<CPubKey> pubkeys;
722-
pubkeys.reserve(entries.size());
723-
for (auto& entry : entries) {
724-
pubkeys.push_back(entry.first);
725-
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
726-
}
727-
728721
output_scripts = MakeScripts(pubkeys, Span{subscripts}, out);
729722
return true;
730723
}

0 commit comments

Comments
 (0)