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