Changeset View
Changeset View
Standalone View
Standalone View
src/script/descriptor.cpp
Show First 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | bool ToPrivateString(const SigningProvider &arg, | ||||
if (m_derive == DeriveType::HARDENED) { | if (m_derive == DeriveType::HARDENED) { | ||||
out += '\''; | out += '\''; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
/** A parsed addr(A) descriptor. */ | /** Base class for all Descriptor implementations. */ | ||||
class AddressDescriptor final : public Descriptor { | class DescriptorImpl : public Descriptor { | ||||
CTxDestination m_destination; | //! Public key arguments for this descriptor (size 1 for PK, PKH; any size | ||||
//! of Multisig). | |||||
public: | const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args; | ||||
AddressDescriptor(CTxDestination destination) | //! The sub-descriptor argument (nullptr for everything but SH). | ||||
: m_destination(std::move(destination)) {} | const std::unique_ptr<Descriptor> m_script_arg; | ||||
//! The string name of the descriptor function. | |||||
bool IsRange() const override { return false; } | const std::string m_name; | ||||
bool IsSolvable() const override { return false; } | |||||
std::string ToString() const override { | protected: | ||||
return "addr(" + EncodeDestination(m_destination, GetConfig()) + ")"; | //! Return a serialization of anything except pubkey and script arguments, | ||||
} | //! to be prepended to those. | ||||
bool ToPrivateString(const SigningProvider &arg, | virtual std::string ToStringExtra() const { return ""; } | ||||
std::string &out) const override { | |||||
out = ToString(); | |||||
return true; | |||||
} | |||||
bool Expand(int pos, const SigningProvider &arg, | |||||
std::vector<CScript> &output_scripts, | |||||
FlatSigningProvider &out) const override { | |||||
output_scripts = | |||||
std::vector<CScript>{GetScriptForDestination(m_destination)}; | |||||
return true; | |||||
} | |||||
}; | |||||
/** A parsed raw(H) descriptor. */ | /** | ||||
class RawDescriptor final : public Descriptor { | * A helper function to construct the scripts for this descriptor. | ||||
CScript m_script; | * | ||||
* This function is invoked once for every CScript produced by evaluating | |||||
* m_script_arg, or just once in case m_script_arg is nullptr. | |||||
* @param pubkeys The evaluations of the m_pubkey_args field. | |||||
* @param script The evaluation of m_script_arg (or nullptr when | |||||
m_script_arg is nullptr). | |||||
* @param out A FlatSigningProvider to put scripts or public keys in that | |||||
are necessary to the solver. | |||||
* The script and pubkeys argument to this function are | |||||
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; | |||||
public: | public: | ||||
RawDescriptor(CScript script) : m_script(std::move(script)) {} | DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, | ||||
std::unique_ptr<Descriptor> script, const std::string &name) | |||||
: m_pubkey_args(std::move(pubkeys)), m_script_arg(std::move(script)), | |||||
m_name(name) {} | |||||
bool IsRange() const override { return false; } | bool IsSolvable() const override { | ||||
bool IsSolvable() const override { return false; } | if (m_script_arg) { | ||||
std::string ToString() const override { | if (!m_script_arg->IsSolvable()) { | ||||
return "raw(" + HexStr(m_script.begin(), m_script.end()) + ")"; | return false; | ||||
} | } | ||||
bool ToPrivateString(const SigningProvider &arg, | |||||
std::string &out) const override { | |||||
out = ToString(); | |||||
return true; | |||||
} | } | ||||
bool Expand(int pos, const SigningProvider &arg, | |||||
std::vector<CScript> &output_scripts, | |||||
FlatSigningProvider &out) const override { | |||||
output_scripts = std::vector<CScript>{m_script}; | |||||
return true; | return true; | ||||
} | } | ||||
}; | |||||
/** A parsed pk(P), pkh(P) descriptor. */ | |||||
class SingleKeyDescriptor final : public Descriptor { | |||||
const std::function<CScript(const CPubKey &)> m_script_fn; | |||||
const std::string m_fn_name; | |||||
std::unique_ptr<PubkeyProvider> m_provider; | |||||
public: | |||||
SingleKeyDescriptor(std::unique_ptr<PubkeyProvider> prov, | |||||
const std::function<CScript(const CPubKey &)> &fn, | |||||
const std::string &name) | |||||
: m_script_fn(fn), m_fn_name(name), m_provider(std::move(prov)) {} | |||||
bool IsRange() const override { return m_provider->IsRange(); } | bool IsRange() const final { | ||||
bool IsSolvable() const override { return true; } | for (const auto &pubkey : m_pubkey_args) { | ||||
std::string ToString() const override { | if (pubkey->IsRange()) { | ||||
return m_fn_name + "(" + m_provider->ToString() + ")"; | |||||
} | |||||
bool ToPrivateString(const SigningProvider &arg, | |||||
std::string &out) const override { | |||||
std::string ret; | |||||
if (!m_provider->ToPrivateString(arg, ret)) { | |||||
return false; | |||||
} | |||||
out = m_fn_name + "(" + std::move(ret) + ")"; | |||||
return true; | return true; | ||||
} | } | ||||
bool Expand(int pos, const SigningProvider &arg, | |||||
std::vector<CScript> &output_scripts, | |||||
FlatSigningProvider &out) const override { | |||||
CPubKey key; | |||||
KeyOriginInfo info; | |||||
if (!m_provider->GetPubKey(pos, arg, key, info)) { | |||||
return false; | |||||
} | } | ||||
output_scripts = std::vector<CScript>{m_script_fn(key)}; | if (m_script_arg) { | ||||
out.origins.emplace(key.GetID(), std::move(info)); | if (m_script_arg->IsRange()) { | ||||
out.pubkeys.emplace(key.GetID(), key); | |||||
return true; | return true; | ||||
} | } | ||||
}; | |||||
CScript P2PKHGetScript(const CPubKey &pubkey) { | |||||
return GetScriptForDestination(pubkey.GetID()); | |||||
} | } | ||||
CScript P2PKGetScript(const CPubKey &pubkey) { | return false; | ||||
return GetScriptForRawPubKey(pubkey); | |||||
} | } | ||||
/** A parsed multi(...) descriptor. */ | bool ToPrivateString(const SigningProvider &arg, | ||||
class MultisigDescriptor : public Descriptor { | std::string &out) const final { | ||||
int m_threshold; | std::string extra = ToStringExtra(); | ||||
std::vector<std::unique_ptr<PubkeyProvider>> m_providers; | size_t pos = extra.size() > 0 ? 1 : 0; | ||||
std::string ret = m_name + "(" + extra; | |||||
public: | for (const auto &pubkey : m_pubkey_args) { | ||||
MultisigDescriptor(int threshold, | if (pos++) { | ||||
std::vector<std::unique_ptr<PubkeyProvider>> providers) | ret += ","; | ||||
: m_threshold(threshold), m_providers(std::move(providers)) {} | |||||
bool IsRange() const override { | |||||
for (const auto &p : m_providers) { | |||||
if (p->IsRange()) { | |||||
return true; | |||||
} | |||||
} | } | ||||
std::string tmp; | |||||
if (!pubkey->ToPrivateString(arg, tmp)) { | |||||
return false; | return false; | ||||
} | } | ||||
ret += std::move(tmp); | |||||
bool IsSolvable() const override { return true; } | |||||
std::string ToString() const override { | |||||
std::string ret = strprintf("multi(%i", m_threshold); | |||||
for (const auto &p : m_providers) { | |||||
ret += "," + p->ToString(); | |||||
} | } | ||||
return std::move(ret) + ")"; | if (m_script_arg) { | ||||
if (pos++) { | |||||
ret += ","; | |||||
} | } | ||||
std::string tmp; | |||||
bool ToPrivateString(const SigningProvider &arg, | if (!m_script_arg->ToPrivateString(arg, tmp)) { | ||||
std::string &out) const override { | |||||
std::string ret = strprintf("multi(%i", m_threshold); | |||||
for (const auto &p : m_providers) { | |||||
std::string sub; | |||||
if (!p->ToPrivateString(arg, sub)) { | |||||
return false; | return false; | ||||
} | } | ||||
ret += "," + std::move(sub); | ret += std::move(tmp); | ||||
} | } | ||||
out = std::move(ret) + ")"; | out = std::move(ret) + ")"; | ||||
return true; | return true; | ||||
} | } | ||||
std::string ToString() const final { | |||||
std::string extra = ToStringExtra(); | |||||
size_t pos = extra.size() > 0 ? 1 : 0; | |||||
std::string ret = m_name + "(" + extra; | |||||
for (const auto &pubkey : m_pubkey_args) { | |||||
if (pos++) { | |||||
ret += ","; | |||||
} | |||||
ret += pubkey->ToString(); | |||||
} | |||||
if (m_script_arg) { | |||||
if (pos++) { | |||||
ret += ","; | |||||
} | |||||
ret += m_script_arg->ToString(); | |||||
} | |||||
return std::move(ret) + ")"; | |||||
} | |||||
bool Expand(int pos, const SigningProvider &arg, | bool Expand(int pos, const SigningProvider &arg, | ||||
std::vector<CScript> &output_scripts, | std::vector<CScript> &output_scripts, | ||||
FlatSigningProvider &out) const override { | FlatSigningProvider &out) const final { | ||||
std::vector<std::pair<CPubKey, KeyOriginInfo>> entries; | std::vector<std::pair<CPubKey, KeyOriginInfo>> entries; | ||||
entries.reserve(m_providers.size()); | entries.reserve(m_pubkey_args.size()); | ||||
// Construct temporary data in `entries`, to avoid producing output in | |||||
// case of failure. | // Construct temporary data in `entries` and `subscripts`, to avoid | ||||
for (const auto &p : m_providers) { | // producing output in case of failure. | ||||
for (const auto &p : m_pubkey_args) { | |||||
entries.emplace_back(); | entries.emplace_back(); | ||||
if (!p->GetPubKey(pos, arg, entries.back().first, | if (!p->GetPubKey(pos, arg, entries.back().first, | ||||
entries.back().second)) { | entries.back().second)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
std::vector<CScript> subscripts; | |||||
if (m_script_arg) { | |||||
FlatSigningProvider subprovider; | |||||
if (!m_script_arg->Expand(pos, arg, subscripts, subprovider)) { | |||||
return false; | |||||
} | |||||
out = Merge(out, subprovider); | |||||
} | |||||
std::vector<CPubKey> pubkeys; | std::vector<CPubKey> pubkeys; | ||||
pubkeys.reserve(entries.size()); | pubkeys.reserve(entries.size()); | ||||
for (auto &entry : entries) { | for (auto &entry : entries) { | ||||
pubkeys.push_back(entry.first); | pubkeys.push_back(entry.first); | ||||
out.origins.emplace(entry.first.GetID(), std::move(entry.second)); | out.origins.emplace(entry.first.GetID(), std::move(entry.second)); | ||||
out.pubkeys.emplace(entry.first.GetID(), entry.first); | out.pubkeys.emplace(entry.first.GetID(), entry.first); | ||||
} | } | ||||
output_scripts = | if (m_script_arg) { | ||||
std::vector<CScript>{GetScriptForMultisig(m_threshold, pubkeys)}; | for (const auto &subscript : subscripts) { | ||||
return true; | out.scripts.emplace(CScriptID(subscript), subscript); | ||||
} | std::vector<CScript> addscripts = | ||||
}; | MakeScripts(pubkeys, &subscript, out); | ||||
for (auto &addscript : addscripts) { | |||||
/** A parsed sh(S) descriptor. */ | output_scripts.push_back(std::move(addscript)); | ||||
class ConvertorDescriptor : public Descriptor { | |||||
const std::function<CScript(const CScript &)> m_convert_fn; | |||||
const std::string m_fn_name; | |||||
std::unique_ptr<Descriptor> m_descriptor; | |||||
public: | |||||
ConvertorDescriptor(std::unique_ptr<Descriptor> descriptor, | |||||
const std::function<CScript(const CScript &)> &fn, | |||||
const std::string &name) | |||||
: m_convert_fn(fn), m_fn_name(name), | |||||
m_descriptor(std::move(descriptor)) {} | |||||
bool IsRange() const override { return m_descriptor->IsRange(); } | |||||
bool IsSolvable() const override { return m_descriptor->IsSolvable(); } | |||||
std::string ToString() const override { | |||||
return m_fn_name + "(" + m_descriptor->ToString() + ")"; | |||||
} | |||||
bool ToPrivateString(const SigningProvider &arg, | |||||
std::string &out) const override { | |||||
std::string ret; | |||||
if (!m_descriptor->ToPrivateString(arg, ret)) { | |||||
return false; | |||||
} | } | ||||
out = m_fn_name + "(" + std::move(ret) + ")"; | |||||
return true; | |||||
} | } | ||||
bool Expand(int pos, const SigningProvider &arg, | } else { | ||||
std::vector<CScript> &output_scripts, | output_scripts = MakeScripts(pubkeys, nullptr, out); | ||||
FlatSigningProvider &out) const override { | |||||
std::vector<CScript> sub; | |||||
if (!m_descriptor->Expand(pos, arg, sub, out)) { | |||||
return false; | |||||
} | |||||
output_scripts.clear(); | |||||
for (const auto &script : sub) { | |||||
CScriptID id(script); | |||||
out.scripts.emplace(CScriptID(script), script); | |||||
output_scripts.push_back(m_convert_fn(script)); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
}; | }; | ||||
CScript ConvertP2SH(const CScript &script) { | /** Construct a vector with one element, which is moved into it. */ | ||||
return GetScriptForDestination(CScriptID(script)); | template <typename T> std::vector<T> Singleton(T elem) { | ||||
std::vector<T> ret; | |||||
ret.emplace_back(std::move(elem)); | |||||
return ret; | |||||
} | } | ||||
/** A parsed combo(P) descriptor. */ | /** A parsed addr(A) descriptor. */ | ||||
class ComboDescriptor final : public Descriptor { | class AddressDescriptor final : public DescriptorImpl { | ||||
std::unique_ptr<PubkeyProvider> m_provider; | const CTxDestination m_destination; | ||||
protected: | |||||
std::string ToStringExtra() const override { | |||||
return EncodeDestination(m_destination, GetConfig()); | |||||
} | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &, | |||||
const CScript *, | |||||
FlatSigningProvider &) const override { | |||||
return Singleton(GetScriptForDestination(m_destination)); | |||||
} | |||||
public: | public: | ||||
ComboDescriptor(std::unique_ptr<PubkeyProvider> provider) | AddressDescriptor(CTxDestination destination) | ||||
: m_provider(std::move(provider)) {} | : DescriptorImpl({}, {}, "addr"), | ||||
m_destination(std::move(destination)) {} | |||||
bool IsSolvable() const final { return false; } | |||||
}; | |||||
bool IsRange() const override { return m_provider->IsRange(); } | /** A parsed raw(H) descriptor. */ | ||||
bool IsSolvable() const override { return true; } | class RawDescriptor final : public DescriptorImpl { | ||||
std::string ToString() const override { | const CScript m_script; | ||||
return "combo(" + m_provider->ToString() + ")"; | |||||
protected: | |||||
std::string ToStringExtra() const override { | |||||
return HexStr(m_script.begin(), m_script.end()); | |||||
} | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &, | |||||
const CScript *, | |||||
FlatSigningProvider &) const override { | |||||
return Singleton(m_script); | |||||
} | } | ||||
bool ToPrivateString(const SigningProvider &arg, | |||||
std::string &out) const override { | public: | ||||
std::string ret; | RawDescriptor(CScript script) | ||||
if (!m_provider->ToPrivateString(arg, ret)) { | : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {} | ||||
return false; | bool IsSolvable() const final { return false; } | ||||
}; | |||||
/** A parsed pk(P) descriptor. */ | |||||
class PKDescriptor final : public DescriptorImpl { | |||||
protected: | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &keys, | |||||
const CScript *, | |||||
FlatSigningProvider &) const override { | |||||
return Singleton(GetScriptForRawPubKey(keys[0])); | |||||
} | } | ||||
out = "combo(" + std::move(ret) + ")"; | |||||
return true; | public: | ||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov) | |||||
: DescriptorImpl(Singleton(std::move(prov)), {}, "pk") {} | |||||
}; | |||||
/** A parsed pkh(P) descriptor. */ | |||||
class PKHDescriptor final : public DescriptorImpl { | |||||
protected: | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &keys, | |||||
const CScript *, | |||||
FlatSigningProvider &) const override { | |||||
return Singleton(GetScriptForDestination(keys[0].GetID())); | |||||
} | } | ||||
bool Expand(int pos, const SigningProvider &arg, | |||||
std::vector<CScript> &output_scripts, | public: | ||||
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) | |||||
: DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} | |||||
}; | |||||
/** A parsed combo(P) descriptor. */ | |||||
class ComboDescriptor final : public DescriptorImpl { | |||||
protected: | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &keys, | |||||
const CScript *, | |||||
FlatSigningProvider &out) const override { | FlatSigningProvider &out) const override { | ||||
CPubKey key; | std::vector<CScript> ret; | ||||
KeyOriginInfo info; | CKeyID id = keys[0].GetID(); | ||||
if (!m_provider->GetPubKey(pos, arg, key, info)) { | // P2PK | ||||
return false; | ret.emplace_back(GetScriptForRawPubKey(keys[0])); | ||||
// P2PKH | |||||
ret.emplace_back(GetScriptForDestination(id)); | |||||
return ret; | |||||
} | } | ||||
CKeyID keyid = key.GetID(); | |||||
{ | public: | ||||
CScript p2pk = GetScriptForRawPubKey(key); | ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) | ||||
CScript p2pkh = GetScriptForDestination(keyid); | : DescriptorImpl(Singleton(std::move(prov)), {}, "combo") {} | ||||
output_scripts = | }; | ||||
std::vector<CScript>{std::move(p2pk), std::move(p2pkh)}; | |||||
out.pubkeys.emplace(keyid, key); | /** A parsed multi(...) descriptor. */ | ||||
out.origins.emplace(keyid, std::move(info)); | class MultisigDescriptor final : public DescriptorImpl { | ||||
const int m_threshold; | |||||
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 { | |||||
return Singleton(GetScriptForMultisig(m_threshold, keys)); | |||||
} | } | ||||
return true; | |||||
public: | |||||
MultisigDescriptor(int threshold, | |||||
std::vector<std::unique_ptr<PubkeyProvider>> providers) | |||||
: DescriptorImpl(std::move(providers), {}, "multi"), | |||||
m_threshold(threshold) {} | |||||
}; | |||||
/** A parsed sh(...) descriptor. */ | |||||
class SHDescriptor final : public DescriptorImpl { | |||||
protected: | |||||
std::vector<CScript> MakeScripts(const std::vector<CPubKey> &, | |||||
const CScript *script, | |||||
FlatSigningProvider &) const override { | |||||
return Singleton(GetScriptForDestination(CScriptID(*script))); | |||||
} | } | ||||
public: | |||||
SHDescriptor(std::unique_ptr<Descriptor> desc) | |||||
: DescriptorImpl({}, std::move(desc), "sh") {} | |||||
}; | }; | ||||
//////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////// | ||||
// Parser // | // Parser // | ||||
//////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////// | ||||
enum class ParseScriptContext { | enum class ParseScriptContext { | ||||
TOP, | TOP, | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | for (size_t i = 1; i < split.size(); ++i) { | ||||
p > 0x7FFFFFFFUL) { | p > 0x7FFFFFFFUL) { | ||||
return false; | return false; | ||||
} | } | ||||
out.push_back(p | (uint32_t(hardened) << 31)); | out.push_back(p | (uint32_t(hardened) << 31)); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** Parse a public key that excludes origin information. */ | ||||
* Parse a public key that excludes origin information. | |||||
*/ | |||||
std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char> &sp, | std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char> &sp, | ||||
FlatSigningProvider &out) { | FlatSigningProvider &out) { | ||||
auto split = Split(sp, '/'); | auto split = Split(sp, '/'); | ||||
std::string str(split[0].begin(), split[0].end()); | std::string str(split[0].begin(), split[0].end()); | ||||
if (split.size() == 1) { | if (split.size() == 1) { | ||||
if (IsHex(str)) { | if (IsHex(str)) { | ||||
std::vector<uint8_t> data = ParseHex(str); | std::vector<uint8_t> data = ParseHex(str); | ||||
CPubKey pubkey(data); | CPubKey pubkey(data); | ||||
Show All 29 Lines | std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char> &sp, | ||||
if (extkey.key.IsValid()) { | if (extkey.key.IsValid()) { | ||||
extpubkey = extkey.Neuter(); | extpubkey = extkey.Neuter(); | ||||
out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key); | out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key); | ||||
} | } | ||||
return std::make_unique<BIP32PubkeyProvider>(extpubkey, std::move(path), | return std::make_unique<BIP32PubkeyProvider>(extpubkey, std::move(path), | ||||
type); | type); | ||||
} | } | ||||
/** | /** Parse a public key including origin information (if enabled). */ | ||||
* Parse a public key including origin information (if enabled). | |||||
*/ | |||||
std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char> &sp, | std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char> &sp, | ||||
FlatSigningProvider &out) { | FlatSigningProvider &out) { | ||||
auto origin_split = Split(sp, ']'); | auto origin_split = Split(sp, ']'); | ||||
if (origin_split.size() > 2) { | if (origin_split.size() > 2) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
if (origin_split.size() == 1) { | if (origin_split.size() == 1) { | ||||
return ParsePubkeyInner(origin_split[0], out); | return ParsePubkeyInner(origin_split[0], out); | ||||
Show All 31 Lines | std::unique_ptr<Descriptor> ParseScript(Span<const char> &sp, | ||||
ParseScriptContext ctx, | ParseScriptContext ctx, | ||||
FlatSigningProvider &out) { | FlatSigningProvider &out) { | ||||
auto expr = Expr(sp); | auto expr = Expr(sp); | ||||
if (Func("pk", expr)) { | if (Func("pk", expr)) { | ||||
auto pubkey = ParsePubkey(expr, out); | auto pubkey = ParsePubkey(expr, out); | ||||
if (!pubkey) { | if (!pubkey) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return std::make_unique<SingleKeyDescriptor>(std::move(pubkey), | return std::make_unique<PKDescriptor>(std::move(pubkey)); | ||||
P2PKGetScript, "pk"); | |||||
} | } | ||||
if (Func("pkh", expr)) { | if (Func("pkh", expr)) { | ||||
auto pubkey = ParsePubkey(expr, out); | auto pubkey = ParsePubkey(expr, out); | ||||
if (!pubkey) { | if (!pubkey) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return std::make_unique<SingleKeyDescriptor>(std::move(pubkey), | return std::make_unique<PKHDescriptor>(std::move(pubkey)); | ||||
P2PKHGetScript, "pkh"); | |||||
} | } | ||||
if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { | if (ctx == ParseScriptContext::TOP && Func("combo", expr)) { | ||||
auto pubkey = ParsePubkey(expr, out); | auto pubkey = ParsePubkey(expr, out); | ||||
if (!pubkey) { | if (!pubkey) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return std::make_unique<ComboDescriptor>(std::move(pubkey)); | return std::make_unique<ComboDescriptor>(std::move(pubkey)); | ||||
} | } | ||||
Show All 37 Lines | if (Func("multi", expr)) { | ||||
return std::make_unique<MultisigDescriptor>(thres, | return std::make_unique<MultisigDescriptor>(thres, | ||||
std::move(providers)); | std::move(providers)); | ||||
} | } | ||||
if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { | if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { | ||||
auto desc = ParseScript(expr, ParseScriptContext::P2SH, out); | auto desc = ParseScript(expr, ParseScriptContext::P2SH, out); | ||||
if (!desc || expr.size()) { | if (!desc || expr.size()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return std::make_unique<ConvertorDescriptor>(std::move(desc), | return std::make_unique<SHDescriptor>(std::move(desc)); | ||||
ConvertP2SH, "sh"); | |||||
} | } | ||||
if (ctx == ParseScriptContext::TOP && Func("addr", expr)) { | if (ctx == ParseScriptContext::TOP && Func("addr", expr)) { | ||||
CTxDestination dest = | CTxDestination dest = | ||||
DecodeDestination(std::string(expr.begin(), expr.end()), Params()); | DecodeDestination(std::string(expr.begin(), expr.end()), Params()); | ||||
if (!IsValidDestination(dest)) { | if (!IsValidDestination(dest)) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return std::make_unique<AddressDescriptor>(std::move(dest)); | return std::make_unique<AddressDescriptor>(std::move(dest)); | ||||
Show All 26 Lines | std::unique_ptr<Descriptor> InferScript(const CScript &script, | ||||
ParseScriptContext ctx, | ParseScriptContext ctx, | ||||
const SigningProvider &provider) { | const SigningProvider &provider) { | ||||
std::vector<std::vector<uint8_t>> data; | std::vector<std::vector<uint8_t>> data; | ||||
txnouttype txntype = Solver(script, data); | txnouttype txntype = Solver(script, data); | ||||
if (txntype == TX_PUBKEY) { | if (txntype == TX_PUBKEY) { | ||||
CPubKey pubkey(data[0].begin(), data[0].end()); | CPubKey pubkey(data[0].begin(), data[0].end()); | ||||
if (pubkey.IsValid()) { | if (pubkey.IsValid()) { | ||||
return std::make_unique<SingleKeyDescriptor>( | return std::make_unique<PKDescriptor>( | ||||
InferPubkey(pubkey, ctx, provider), P2PKGetScript, "pk"); | InferPubkey(pubkey, ctx, provider)); | ||||
} | } | ||||
} | } | ||||
if (txntype == TX_PUBKEYHASH) { | if (txntype == TX_PUBKEYHASH) { | ||||
uint160 hash(data[0]); | uint160 hash(data[0]); | ||||
CKeyID keyid(hash); | CKeyID keyid(hash); | ||||
CPubKey pubkey; | CPubKey pubkey; | ||||
if (provider.GetPubKey(keyid, pubkey)) { | if (provider.GetPubKey(keyid, pubkey)) { | ||||
return std::make_unique<SingleKeyDescriptor>( | return std::make_unique<PKHDescriptor>( | ||||
InferPubkey(pubkey, ctx, provider), P2PKHGetScript, "pkh"); | InferPubkey(pubkey, ctx, provider)); | ||||
} | } | ||||
} | } | ||||
if (txntype == TX_MULTISIG) { | if (txntype == TX_MULTISIG) { | ||||
std::vector<std::unique_ptr<PubkeyProvider>> providers; | std::vector<std::unique_ptr<PubkeyProvider>> providers; | ||||
for (size_t i = 1; i + 1 < data.size(); ++i) { | for (size_t i = 1; i + 1 < data.size(); ++i) { | ||||
CPubKey pubkey(data[i].begin(), data[i].end()); | CPubKey pubkey(data[i].begin(), data[i].end()); | ||||
providers.push_back(InferPubkey(pubkey, ctx, provider)); | providers.push_back(InferPubkey(pubkey, ctx, provider)); | ||||
} | } | ||||
return std::make_unique<MultisigDescriptor>((int)data[0][0], | return std::make_unique<MultisigDescriptor>((int)data[0][0], | ||||
std::move(providers)); | std::move(providers)); | ||||
} | } | ||||
if (txntype == TX_SCRIPTHASH && ctx == ParseScriptContext::TOP) { | if (txntype == TX_SCRIPTHASH && ctx == ParseScriptContext::TOP) { | ||||
uint160 hash(data[0]); | uint160 hash(data[0]); | ||||
CScriptID scriptid(hash); | CScriptID scriptid(hash); | ||||
CScript subscript; | CScript subscript; | ||||
if (provider.GetCScript(scriptid, subscript)) { | if (provider.GetCScript(scriptid, subscript)) { | ||||
auto sub = | auto sub = | ||||
InferScript(subscript, ParseScriptContext::P2SH, provider); | InferScript(subscript, ParseScriptContext::P2SH, provider); | ||||
if (sub) { | if (sub) { | ||||
return std::make_unique<ConvertorDescriptor>(std::move(sub), | return std::make_unique<SHDescriptor>(std::move(sub)); | ||||
ConvertP2SH, "sh"); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
CTxDestination dest; | CTxDestination dest; | ||||
if (ExtractDestination(script, dest)) { | if (ExtractDestination(script, dest)) { | ||||
if (GetScriptForDestination(dest) == script) { | if (GetScriptForDestination(dest) == script) { | ||||
return std::make_unique<AddressDescriptor>(std::move(dest)); | return std::make_unique<AddressDescriptor>(std::move(dest)); | ||||
Show All 22 Lines |