Skip to content

Commit 4441c6f

Browse files
committed
Make DescriptorImpl support multiple subscripts
So far, no descriptor exists that supports more than one sub-script descriptor. This will change with taproot, so prepare for this by changing the m_subdescriptor_arg from a unique_ptr to a vector of unique_ptr's.
1 parent a917478 commit 4441c6f

File tree

1 file changed

+47
-49
lines changed

1 file changed

+47
-49
lines changed

src/script/descriptor.cpp

Lines changed: 47 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -481,34 +481,35 @@ class DescriptorImpl : public Descriptor
481481
const std::string m_name;
482482

483483
protected:
484-
//! The sub-descriptor argument (nullptr for everything but SH and WSH).
484+
//! The sub-descriptor arguments (empty for everything but SH and WSH).
485485
//! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
486486
//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
487487
//! Subdescriptors can only ever generate a single script.
488-
const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg;
488+
const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;
489489

490490
//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
491491
virtual std::string ToStringExtra() const { return ""; }
492492

493493
/** A helper function to construct the scripts for this descriptor.
494494
*
495495
* This function is invoked once by ExpandHelper.
496-
496+
*
497497
* @param pubkeys The evaluations of the m_pubkey_args field.
498-
* @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr).
498+
* @param script The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).
499499
* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
500500
* The origin info of the provided pubkeys is automatically added.
501501
* @return A vector with scriptPubKeys for this descriptor.
502502
*/
503-
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
503+
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0;
504504

505505
public:
506-
DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_arg(std::move(script)) {}
506+
DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}
507+
DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::unique_ptr<DescriptorImpl> script, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(Vector(std::move(script))) {}
507508

508509
bool IsSolvable() const override
509510
{
510-
if (m_subdescriptor_arg) {
511-
if (!m_subdescriptor_arg->IsSolvable()) return false;
511+
for (const auto& arg : m_subdescriptor_args) {
512+
if (!arg->IsSolvable()) return false;
512513
}
513514
return true;
514515
}
@@ -518,8 +519,8 @@ class DescriptorImpl : public Descriptor
518519
for (const auto& pubkey : m_pubkey_args) {
519520
if (pubkey->IsRange()) return true;
520521
}
521-
if (m_subdescriptor_arg) {
522-
if (m_subdescriptor_arg->IsRange()) return true;
522+
for (const auto& arg : m_subdescriptor_args) {
523+
if (arg->IsRange()) return true;
523524
}
524525
return false;
525526
}
@@ -541,10 +542,10 @@ class DescriptorImpl : public Descriptor
541542
}
542543
ret += std::move(tmp);
543544
}
544-
if (m_subdescriptor_arg) {
545+
for (const auto& scriptarg : m_subdescriptor_args) {
545546
if (pos++) ret += ",";
546547
std::string tmp;
547-
if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv, normalized)) return false;
548+
if (!scriptarg->ToStringHelper(arg, tmp, priv, normalized)) return false;
548549
ret += std::move(tmp);
549550
}
550551
out = std::move(ret) + ")";
@@ -577,30 +578,29 @@ class DescriptorImpl : public Descriptor
577578
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
578579
entries.reserve(m_pubkey_args.size());
579580

580-
// Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
581+
// Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
581582
for (const auto& p : m_pubkey_args) {
582583
entries.emplace_back();
583584
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
584585
}
585586
std::vector<CScript> subscripts;
586-
if (m_subdescriptor_arg) {
587-
FlatSigningProvider subprovider;
588-
if (!m_subdescriptor_arg->ExpandHelper(pos, arg, read_cache, subscripts, subprovider, write_cache)) return false;
589-
assert(subscripts.size() == 1);
590-
out = Merge(out, subprovider);
587+
FlatSigningProvider subprovider;
588+
for (const auto& subarg : m_subdescriptor_args) {
589+
std::vector<CScript> outscripts;
590+
if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
591+
assert(outscripts.size() == 1);
592+
subscripts.emplace_back(std::move(outscripts[0]));
591593
}
594+
out = Merge(std::move(out), std::move(subprovider));
592595

593596
std::vector<CPubKey> pubkeys;
594597
pubkeys.reserve(entries.size());
595598
for (auto& entry : entries) {
596599
pubkeys.push_back(entry.first);
597600
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
598601
}
599-
if (m_subdescriptor_arg) {
600-
output_scripts = MakeScripts(pubkeys, &subscripts[0], out);
601-
} else {
602-
output_scripts = MakeScripts(pubkeys, nullptr, out);
603-
}
602+
603+
output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
604604
return true;
605605
}
606606

@@ -621,10 +621,8 @@ class DescriptorImpl : public Descriptor
621621
if (!p->GetPrivKey(pos, provider, key)) continue;
622622
out.keys.emplace(key.GetPubKey().GetID(), key);
623623
}
624-
if (m_subdescriptor_arg) {
625-
FlatSigningProvider subprovider;
626-
m_subdescriptor_arg->ExpandPrivate(pos, provider, subprovider);
627-
out = Merge(out, subprovider);
624+
for (const auto& arg : m_subdescriptor_args) {
625+
arg->ExpandPrivate(pos, provider, out);
628626
}
629627
}
630628

@@ -637,9 +635,9 @@ class AddressDescriptor final : public DescriptorImpl
637635
const CTxDestination m_destination;
638636
protected:
639637
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
640-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
638+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
641639
public:
642-
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
640+
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {}
643641
bool IsSolvable() const final { return false; }
644642

645643
std::optional<OutputType> GetOutputType() const override
@@ -663,9 +661,9 @@ class RawDescriptor final : public DescriptorImpl
663661
const CScript m_script;
664662
protected:
665663
std::string ToStringExtra() const override { return HexStr(m_script); }
666-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
664+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); }
667665
public:
668-
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
666+
RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {}
669667
bool IsSolvable() const final { return false; }
670668

671669
std::optional<OutputType> GetOutputType() const override
@@ -689,24 +687,24 @@ class RawDescriptor final : public DescriptorImpl
689687
class PKDescriptor final : public DescriptorImpl
690688
{
691689
protected:
692-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
690+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
693691
public:
694-
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
692+
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {}
695693
bool IsSingleType() const final { return true; }
696694
};
697695

698696
/** A parsed pkh(P) descriptor. */
699697
class PKHDescriptor final : public DescriptorImpl
700698
{
701699
protected:
702-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
700+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
703701
{
704702
CKeyID id = keys[0].GetID();
705703
out.pubkeys.emplace(id, keys[0]);
706704
return Vector(GetScriptForDestination(PKHash(id)));
707705
}
708706
public:
709-
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pkh") {}
707+
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
710708
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
711709
bool IsSingleType() const final { return true; }
712710
};
@@ -715,14 +713,14 @@ class PKHDescriptor final : public DescriptorImpl
715713
class WPKHDescriptor final : public DescriptorImpl
716714
{
717715
protected:
718-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
716+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
719717
{
720718
CKeyID id = keys[0].GetID();
721719
out.pubkeys.emplace(id, keys[0]);
722720
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
723721
}
724722
public:
725-
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "wpkh") {}
723+
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
726724
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
727725
bool IsSingleType() const final { return true; }
728726
};
@@ -731,7 +729,7 @@ class WPKHDescriptor final : public DescriptorImpl
731729
class ComboDescriptor final : public DescriptorImpl
732730
{
733731
protected:
734-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
732+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
735733
{
736734
std::vector<CScript> ret;
737735
CKeyID id = keys[0].GetID();
@@ -747,7 +745,7 @@ class ComboDescriptor final : public DescriptorImpl
747745
return ret;
748746
}
749747
public:
750-
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "combo") {}
748+
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
751749
bool IsSingleType() const final { return false; }
752750
};
753751

@@ -758,7 +756,7 @@ class MultisigDescriptor final : public DescriptorImpl
758756
const bool m_sorted;
759757
protected:
760758
std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
761-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override {
759+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
762760
if (m_sorted) {
763761
std::vector<CPubKey> sorted_keys(keys);
764762
std::sort(sorted_keys.begin(), sorted_keys.end());
@@ -767,27 +765,27 @@ class MultisigDescriptor final : public DescriptorImpl
767765
return Vector(GetScriptForMultisig(m_threshold, keys));
768766
}
769767
public:
770-
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) {}
768+
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) {}
771769
bool IsSingleType() const final { return true; }
772770
};
773771

774772
/** A parsed sh(...) descriptor. */
775773
class SHDescriptor final : public DescriptorImpl
776774
{
777775
protected:
778-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider& out) const override
776+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
779777
{
780-
auto ret = Vector(GetScriptForDestination(ScriptHash(*script)));
781-
if (ret.size()) out.scripts.emplace(CScriptID(*script), *script);
778+
auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0])));
779+
if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
782780
return ret;
783781
}
784782
public:
785783
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
786784

787785
std::optional<OutputType> GetOutputType() const override
788786
{
789-
assert(m_subdescriptor_arg);
790-
if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
787+
assert(m_subdescriptor_args.size() == 1);
788+
if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
791789
return OutputType::LEGACY;
792790
}
793791
bool IsSingleType() const final { return true; }
@@ -797,10 +795,10 @@ class SHDescriptor final : public DescriptorImpl
797795
class WSHDescriptor final : public DescriptorImpl
798796
{
799797
protected:
800-
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider& out) const override
798+
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
801799
{
802-
auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(*script)));
803-
if (ret.size()) out.scripts.emplace(CScriptID(*script), *script);
800+
auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0])));
801+
if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
804802
return ret;
805803
}
806804
public:

0 commit comments

Comments
 (0)