mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-27 14:01:12 +02:00
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.
This commit is contained in:
@@ -481,11 +481,11 @@ class DescriptorImpl : public Descriptor
|
||||
const std::string m_name;
|
||||
|
||||
protected:
|
||||
//! The sub-descriptor argument (nullptr for everything but SH and WSH).
|
||||
//! The sub-descriptor arguments (empty for everything but SH and WSH).
|
||||
//! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
|
||||
//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
|
||||
//! Subdescriptors can only ever generate a single script.
|
||||
const std::unique_ptr<DescriptorImpl> m_subdescriptor_arg;
|
||||
const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;
|
||||
|
||||
//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
|
||||
virtual std::string ToStringExtra() const { return ""; }
|
||||
@@ -493,22 +493,23 @@ protected:
|
||||
/** A helper function to construct the scripts for this descriptor.
|
||||
*
|
||||
* This function is invoked once by ExpandHelper.
|
||||
|
||||
*
|
||||
* @param pubkeys The evaluations of the m_pubkey_args field.
|
||||
* @param script The evaluation of m_subdescriptor_arg (or nullptr when m_subdescriptor_arg is nullptr).
|
||||
* @param script The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).
|
||||
* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
|
||||
* The origin info of the provided pubkeys is automatically added.
|
||||
* @return A vector with scriptPubKeys for this descriptor.
|
||||
*/
|
||||
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
|
||||
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0;
|
||||
|
||||
public:
|
||||
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)) {}
|
||||
DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}
|
||||
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))) {}
|
||||
|
||||
bool IsSolvable() const override
|
||||
{
|
||||
if (m_subdescriptor_arg) {
|
||||
if (!m_subdescriptor_arg->IsSolvable()) return false;
|
||||
for (const auto& arg : m_subdescriptor_args) {
|
||||
if (!arg->IsSolvable()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -518,8 +519,8 @@ public:
|
||||
for (const auto& pubkey : m_pubkey_args) {
|
||||
if (pubkey->IsRange()) return true;
|
||||
}
|
||||
if (m_subdescriptor_arg) {
|
||||
if (m_subdescriptor_arg->IsRange()) return true;
|
||||
for (const auto& arg : m_subdescriptor_args) {
|
||||
if (arg->IsRange()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -541,10 +542,10 @@ public:
|
||||
}
|
||||
ret += std::move(tmp);
|
||||
}
|
||||
if (m_subdescriptor_arg) {
|
||||
for (const auto& scriptarg : m_subdescriptor_args) {
|
||||
if (pos++) ret += ",";
|
||||
std::string tmp;
|
||||
if (!m_subdescriptor_arg->ToStringHelper(arg, tmp, priv, normalized)) return false;
|
||||
if (!scriptarg->ToStringHelper(arg, tmp, priv, normalized)) return false;
|
||||
ret += std::move(tmp);
|
||||
}
|
||||
out = std::move(ret) + ")";
|
||||
@@ -577,18 +578,20 @@ public:
|
||||
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
|
||||
entries.reserve(m_pubkey_args.size());
|
||||
|
||||
// Construct temporary data in `entries` and `subscripts`, to avoid producing output in case of failure.
|
||||
// Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
|
||||
for (const auto& p : m_pubkey_args) {
|
||||
entries.emplace_back();
|
||||
if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
|
||||
}
|
||||
std::vector<CScript> subscripts;
|
||||
if (m_subdescriptor_arg) {
|
||||
FlatSigningProvider subprovider;
|
||||
if (!m_subdescriptor_arg->ExpandHelper(pos, arg, read_cache, subscripts, subprovider, write_cache)) return false;
|
||||
assert(subscripts.size() == 1);
|
||||
out = Merge(out, subprovider);
|
||||
FlatSigningProvider subprovider;
|
||||
for (const auto& subarg : m_subdescriptor_args) {
|
||||
std::vector<CScript> outscripts;
|
||||
if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
|
||||
assert(outscripts.size() == 1);
|
||||
subscripts.emplace_back(std::move(outscripts[0]));
|
||||
}
|
||||
out = Merge(std::move(out), std::move(subprovider));
|
||||
|
||||
std::vector<CPubKey> pubkeys;
|
||||
pubkeys.reserve(entries.size());
|
||||
@@ -596,11 +599,8 @@ public:
|
||||
pubkeys.push_back(entry.first);
|
||||
out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
|
||||
}
|
||||
if (m_subdescriptor_arg) {
|
||||
output_scripts = MakeScripts(pubkeys, &subscripts[0], out);
|
||||
} else {
|
||||
output_scripts = MakeScripts(pubkeys, nullptr, out);
|
||||
}
|
||||
|
||||
output_scripts = MakeScripts(pubkeys, MakeSpan(subscripts), out);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -621,10 +621,8 @@ public:
|
||||
if (!p->GetPrivKey(pos, provider, key)) continue;
|
||||
out.keys.emplace(key.GetPubKey().GetID(), key);
|
||||
}
|
||||
if (m_subdescriptor_arg) {
|
||||
FlatSigningProvider subprovider;
|
||||
m_subdescriptor_arg->ExpandPrivate(pos, provider, subprovider);
|
||||
out = Merge(out, subprovider);
|
||||
for (const auto& arg : m_subdescriptor_args) {
|
||||
arg->ExpandPrivate(pos, provider, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,9 +635,9 @@ class AddressDescriptor final : public DescriptorImpl
|
||||
const CTxDestination m_destination;
|
||||
protected:
|
||||
std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
|
||||
public:
|
||||
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, {}, "addr"), m_destination(std::move(destination)) {}
|
||||
AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {}
|
||||
bool IsSolvable() const final { return false; }
|
||||
|
||||
std::optional<OutputType> GetOutputType() const override
|
||||
@@ -663,9 +661,9 @@ class RawDescriptor final : public DescriptorImpl
|
||||
const CScript m_script;
|
||||
protected:
|
||||
std::string ToStringExtra() const override { return HexStr(m_script); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); }
|
||||
public:
|
||||
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
|
||||
RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {}
|
||||
bool IsSolvable() const final { return false; }
|
||||
|
||||
std::optional<OutputType> GetOutputType() const override
|
||||
@@ -689,9 +687,9 @@ public:
|
||||
class PKDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForRawPubKey(keys[0])); }
|
||||
public:
|
||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), {}, "pk") {}
|
||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pk") {}
|
||||
bool IsSingleType() const final { return true; }
|
||||
};
|
||||
|
||||
@@ -699,14 +697,14 @@ public:
|
||||
class PKHDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
|
||||
{
|
||||
CKeyID id = keys[0].GetID();
|
||||
out.pubkeys.emplace(id, keys[0]);
|
||||
return Vector(GetScriptForDestination(PKHash(id)));
|
||||
}
|
||||
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; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
};
|
||||
@@ -715,14 +713,14 @@ public:
|
||||
class WPKHDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
|
||||
{
|
||||
CKeyID id = keys[0].GetID();
|
||||
out.pubkeys.emplace(id, keys[0]);
|
||||
return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
|
||||
}
|
||||
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; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
};
|
||||
@@ -731,7 +729,7 @@ public:
|
||||
class ComboDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
|
||||
{
|
||||
std::vector<CScript> ret;
|
||||
CKeyID id = keys[0].GetID();
|
||||
@@ -747,7 +745,7 @@ protected:
|
||||
return ret;
|
||||
}
|
||||
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; }
|
||||
};
|
||||
|
||||
@@ -758,7 +756,7 @@ class MultisigDescriptor final : public DescriptorImpl
|
||||
const bool m_sorted;
|
||||
protected:
|
||||
std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override {
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
|
||||
if (m_sorted) {
|
||||
std::vector<CPubKey> sorted_keys(keys);
|
||||
std::sort(sorted_keys.begin(), sorted_keys.end());
|
||||
@@ -767,7 +765,7 @@ protected:
|
||||
return Vector(GetScriptForMultisig(m_threshold, keys));
|
||||
}
|
||||
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; }
|
||||
};
|
||||
|
||||
@@ -775,10 +773,10 @@ public:
|
||||
class SHDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider& out) const override
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
|
||||
{
|
||||
auto ret = Vector(GetScriptForDestination(ScriptHash(*script)));
|
||||
if (ret.size()) out.scripts.emplace(CScriptID(*script), *script);
|
||||
auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0])));
|
||||
if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
|
||||
return ret;
|
||||
}
|
||||
public:
|
||||
@@ -786,8 +784,8 @@ public:
|
||||
|
||||
std::optional<OutputType> GetOutputType() const override
|
||||
{
|
||||
assert(m_subdescriptor_arg);
|
||||
if (m_subdescriptor_arg->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
|
||||
assert(m_subdescriptor_args.size() == 1);
|
||||
if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
|
||||
return OutputType::LEGACY;
|
||||
}
|
||||
bool IsSingleType() const final { return true; }
|
||||
@@ -797,10 +795,10 @@ public:
|
||||
class WSHDescriptor final : public DescriptorImpl
|
||||
{
|
||||
protected:
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider& out) const override
|
||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
|
||||
{
|
||||
auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(*script)));
|
||||
if (ret.size()) out.scripts.emplace(CScriptID(*script), *script);
|
||||
auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0])));
|
||||
if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
|
||||
return ret;
|
||||
}
|
||||
public:
|
||||
|
Reference in New Issue
Block a user