27 typedef std::vector<uint32_t> KeyPath;
29 std::string FormatKeyPath(
const KeyPath& path)
34 if (i >> 31) ret +=
'\'';
42 virtual ~PubkeyProvider() =
default;
48 virtual bool IsRange()
const = 0;
51 virtual size_t GetSize()
const = 0;
54 virtual std::string ToString()
const = 0;
57 virtual bool ToPrivateString(
const SigningProvider& arg, std::string& out)
const = 0;
61 class ConstPubkeyProvider final :
public PubkeyProvider
66 explicit ConstPubkeyProvider(
const CPubKey& pubkey) : m_pubkey(pubkey) {}
72 bool IsRange()
const override {
return false; }
73 size_t GetSize()
const override {
return m_pubkey.
size(); }
74 std::string ToString()
const override {
return HexStr(m_pubkey); }
75 bool ToPrivateString(
const SigningProvider& arg, std::string& ret)
const override
78 if (!arg.
GetKey(m_pubkey.GetID(), key))
return false;
84 enum class DeriveType {
91 class BIP32PubkeyProvider final :
public PubkeyProvider
100 if (!arg.
GetKey(m_extkey.pubkey.GetID(), key))
return false;
101 ret.
nDepth = m_extkey.nDepth;
102 std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint + 4, ret.
vchFingerprint);
103 ret.
nChild = m_extkey.nChild;
109 bool IsHardened()
const
111 if (m_derive == DeriveType::HARDENED)
return true;
112 for (
auto entry : m_path) {
113 if (entry >> 31)
return true;
119 BIP32PubkeyProvider(
const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(
std::move(path)), m_derive(derive) {}
120 bool IsRange()
const override {
return m_derive != DeriveType::NO; }
121 size_t GetSize()
const override {
return 33; }
126 if (!GetExtKey(arg, key))
return false;
127 for (
auto entry : m_path) {
130 if (m_derive == DeriveType::UNHARDENED) key.
Derive(key, pos);
131 if (m_derive == DeriveType::HARDENED) key.
Derive(key, pos | 0x80000000UL);
136 for (
auto entry : m_path) {
139 if (m_derive == DeriveType::UNHARDENED) key.
Derive(key, pos);
140 assert(m_derive != DeriveType::HARDENED);
145 std::string ToString()
const override
150 if (m_derive == DeriveType::HARDENED) ret +=
'\'';
154 bool ToPrivateString(
const SigningProvider& arg, std::string& out)
const override
157 if (!GetExtKey(arg, key))
return false;
161 if (m_derive == DeriveType::HARDENED) out +=
'\'';
168 class AddressDescriptor final :
public Descriptor
173 explicit AddressDescriptor(
CTxDestination destination) : m_destination(
std::move(destination)) {}
175 bool IsRange()
const override {
return false; }
191 explicit RawDescriptor(
CScript script) : m_script(
std::move(script)) {}
193 bool IsRange()
const override {
return false; }
194 std::string
ToString()
const override {
return "raw(" +
HexStr(m_script) +
")"; }
198 output_scripts = std::vector<CScript>{m_script};
204 class SingleKeyDescriptor final :
public Descriptor
207 const std::string m_fn_name;
208 std::unique_ptr<PubkeyProvider> m_provider;
211 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)) {}
213 bool IsRange()
const override {
return m_provider->IsRange(); }
214 std::string
ToString()
const override {
return m_fn_name +
"(" + m_provider->ToString() +
")"; }
218 if (!m_provider->ToPrivateString(arg, ret))
return false;
219 out = m_fn_name +
"(" + std::move(ret) +
")";
225 if (!m_provider->GetPubKey(pos, arg, key))
return false;
226 output_scripts = std::vector<CScript>{m_script_fn(key)};
239 std::vector<std::unique_ptr<PubkeyProvider>> m_providers;
242 MultisigDescriptor(
int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers) : m_threshold(threshold), m_providers(
std::move(providers)) {}
246 for (
const auto& p : m_providers) {
247 if (p->IsRange())
return true;
252 std::string
ToString()
const override
254 std::string ret =
strprintf(
"multi(%i", m_threshold);
255 for (
const auto& p : m_providers) {
256 ret +=
"," + p->ToString();
258 return std::move(ret) +
")";
263 std::string ret =
strprintf(
"multi(%i", m_threshold);
264 for (
const auto& p : m_providers) {
266 if (!p->ToPrivateString(arg, sub))
return false;
267 ret +=
"," + std::move(sub);
269 out = std::move(ret) +
")";
275 std::vector<CPubKey> pubkeys;
276 pubkeys.reserve(m_providers.size());
277 for (
const auto& p : m_providers) {
279 if (!p->GetPubKey(pos, arg, key))
return false;
280 pubkeys.push_back(key);
282 for (
const CPubKey& key : pubkeys) {
294 const std::string m_fn_name;
295 std::unique_ptr<Descriptor> m_descriptor;
298 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)) {}
300 bool IsRange()
const override {
return m_descriptor->IsRange(); }
301 std::string
ToString()
const override {
return m_fn_name +
"(" + m_descriptor->ToString() +
")"; }
305 if (!m_descriptor->ToPrivateString(arg, ret))
return false;
306 out = m_fn_name +
"(" + std::move(ret) +
")";
311 std::vector<CScript> sub;
312 if (!m_descriptor->Expand(pos, arg, sub, out))
return false;
313 output_scripts.clear();
314 for (
const auto& script : sub) {
317 output_scripts.push_back(m_convert_fn(script));
326 class ComboDescriptor final :
public Descriptor
328 std::unique_ptr<PubkeyProvider> m_provider;
331 explicit ComboDescriptor(std::unique_ptr<PubkeyProvider> provider) : m_provider(
std::move(provider)) {}
333 bool IsRange()
const override {
return m_provider->IsRange(); }
334 std::string
ToString()
const override {
return "combo(" + m_provider->ToString() +
")"; }
338 if (!m_provider->ToPrivateString(arg, ret))
return false;
339 out =
"combo(" + std::move(ret) +
")";
345 if (!m_provider->GetPubKey(pos, arg, key))
return false;
350 output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)};
351 out.
pubkeys.emplace(keyid, key);
361 enum class ParseScriptContext {
369 if ((
size_t)sp.
size() >= str.size() && std::equal(str.begin(), str.end(), sp.
begin())) {
379 if ((
size_t)sp.
size() >= str.size() + 2 && sp[str.size()] ==
'(' && sp[sp.
size() - 1] ==
')' && std::equal(str.begin(), str.end(), sp.
begin())) {
380 sp = sp.
subspan(str.size() + 1, sp.
size() - str.size() - 2);
390 auto it = sp.
begin();
391 while (it != sp.
end()) {
394 }
else if (level && *it ==
')') {
396 }
else if (level == 0 && (*it ==
')' || *it ==
',')) {
409 std::vector<Span<const char>> ret;
410 auto it = sp.
begin();
412 while (it != sp.
end()) {
414 ret.emplace_back(start, it);
419 ret.emplace_back(start, it);
426 for (
size_t i = 1; i < split.size(); ++i) {
428 bool hardened =
false;
429 if (elem.
size() > 0 && (elem[elem.
size() - 1] ==
'\'' || elem[elem.
size() - 1] ==
'h')) {
434 if (!
ParseUInt32(std::string(elem.
begin(), elem.
end()), &p) || p > 0x7FFFFFFFUL)
return false;
435 out.push_back(p | (((uint32_t)hardened) << 31));
442 auto split = Split(sp,
'/');
443 std::string str(split[0].begin(), split[0].end());
444 if (split.size() == 1) {
446 std::vector<unsigned char> data =
ParseHex(str);
448 if (pubkey.
IsFullyValid() && (permit_uncompressed || pubkey.
IsCompressed()))
return std::make_unique<ConstPubkeyProvider>(pubkey);
454 return std::make_unique<ConstPubkeyProvider>(pubkey);
461 DeriveType type = DeriveType::NO;
462 if (split.back() ==
MakeSpan(
"*").first(1)) {
464 type = DeriveType::UNHARDENED;
465 }
else if (split.back() ==
MakeSpan(
"*'").first(2) || split.back() ==
MakeSpan(
"*h").first(2)) {
467 type = DeriveType::HARDENED;
469 if (!ParseKeyPath(split, path))
return nullptr;
471 extpubkey = extkey.
Neuter();
474 return std::make_unique<BIP32PubkeyProvider>(extpubkey, std::move(path), type);
480 auto expr = Expr(sp);
481 if (Func(
"pk", expr)) {
482 auto pubkey = ParsePubkey(expr,
true, out);
483 if (!pubkey)
return nullptr;
484 return std::make_unique<SingleKeyDescriptor>(std::move(pubkey), P2PKGetScript,
"pk");
486 if (Func(
"pkh", expr)) {
487 auto pubkey = ParsePubkey(expr,
true, out);
488 if (!pubkey)
return nullptr;
489 return std::make_unique<SingleKeyDescriptor>(std::move(pubkey), P2PKHGetScript,
"pkh");
491 if (ctx == ParseScriptContext::TOP && Func(
"combo", expr)) {
492 auto pubkey = ParsePubkey(expr,
true, out);
493 if (!pubkey)
return nullptr;
494 return std::make_unique<ComboDescriptor>(std::move(pubkey));
496 if (Func(
"multi", expr)) {
497 auto threshold = Expr(expr);
499 std::vector<std::unique_ptr<PubkeyProvider>> providers;
500 if (!
ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres))
return nullptr;
501 size_t script_size = 0;
502 while (expr.size()) {
503 if (!Const(
",", expr))
return nullptr;
504 auto arg = Expr(expr);
505 auto pk = ParsePubkey(arg,
true, out);
506 if (!pk)
return nullptr;
507 script_size += pk->GetSize() + 1;
508 providers.emplace_back(std::move(pk));
510 if (providers.size() < 1 || providers.size() > 16 || thres < 1 || thres > providers.size())
return nullptr;
511 if (ctx == ParseScriptContext::TOP) {
512 if (providers.size() > 3)
return nullptr;
514 if (ctx == ParseScriptContext::P2SH) {
515 if (script_size + 3 > 520)
return nullptr;
517 return std::make_unique<MultisigDescriptor>(thres, std::move(providers));
519 if (ctx == ParseScriptContext::TOP && Func(
"sh", expr)) {
520 auto desc =
ParseScript(expr, ParseScriptContext::P2SH, out);
521 if (!desc || expr.size())
return nullptr;
522 return std::make_unique<ConvertorDescriptor>(std::move(desc), ConvertP2SH,
"sh");
524 if (ctx == ParseScriptContext::TOP && Func(
"addr", expr)) {
527 return std::make_unique<AddressDescriptor>(std::move(dest));
529 if (ctx == ParseScriptContext::TOP && Func(
"raw", expr)) {
530 std::string str(expr.begin(), expr.end());
531 if (!
IsHex(str))
return nullptr;
533 return std::make_unique<RawDescriptor>(
CScript(bytes.begin(), bytes.end()));
543 auto ret =
ParseScript(sp, ParseScriptContext::TOP, out);
544 if (sp.
size() == 0 && ret)
return ret;
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
CPubKey GetPubKey() const
Compute the public key from a private key.
A reference to a CKey: the Hash160 of its serialized public key.
An encapsulated public key.
bool IsCompressed() const
Check whether this is a compressed public key.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
Serialized script, used inside transaction inputs and outputs.
A reference to a CScript: the Hash160 of its serialization (see script.h)
An interface to be implemented by keystores that support signing.
virtual bool GetKey(const CKeyID &address, CKey &key) const
A Span is an object that can refer to a contiguous sequence of objects.
constexpr std::size_t size() const noexcept
constexpr C * end() const noexcept
constexpr C * begin() const noexcept
CONSTEXPR_IF_NOT_DEBUG Span< C > first(std::size_t count) const noexcept
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
CScript ParseScript(std::string s)
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out)
Parse a descriptor string.
std::string EncodeSecret(const CKey &key)
CKey DecodeSecret(const std::string &str)
std::string EncodeExtPubKey(const CExtPubKey &key)
std::string EncodeExtKey(const CExtKey &key)
CExtPubKey DecodeExtPubKey(const std::string &str)
CExtKey DecodeExtKey(const std::string &str)
bool IsValidDestination(const CWDestination &address)
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
CWDestination DecodeDestination(const std::string &strAddress)
constexpr Span< A > MakeSpan(A(&a)[N])
MakeSpan for arrays:
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
unsigned char vchFingerprint[4]
CExtPubKey Neuter() const
bool Derive(CExtKey &out, unsigned int nChild) const
bool Derive(CExtPubKey &out, unsigned int nChild) const
Interface for parsed descriptor objects.
virtual std::string ToString() const =0
Convert the descriptor back to a string, undoing parsing.
virtual bool Expand(int pos, const SigningProvider &provider, std::vector< CScript > &output_scripts, FlatSigningProvider &out) const =0
Expand a descriptor at a specified position.
virtual bool IsRange() const =0
Whether the expansion of this descriptor depends on the position.
virtual bool ToPrivateString(const SigningProvider &provider, std::string &out) const =0
Convert the descriptor to a private string.
std::map< CKeyID, CPubKey > pubkeys
std::map< CKeyID, CKey > keys
std::map< CScriptID, CScript > scripts
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< unsigned char > ParseHex(const char *psz)
bool ParseUInt32(const std::string &str, uint32_t *out)
Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
bool IsHex(const std::string &str)