BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
descriptor.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <script/descriptor.h>
6 
7 #include <key_io.h>
8 #include <pubkey.h>
9 #include <script/script.h>
10 #include <script/standard.h>
11 
12 #include <span.h>
13 #include <util.h>
14 #include <utilstrencodings.h>
15 
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 namespace {
21 
23 // Internal representation //
25 
26 typedef std::vector<uint32_t> KeyPath;
27 
28 std::string FormatKeyPath(const KeyPath& path)
29 {
30  std::string ret;
31  for (auto i : path) {
32  ret += strprintf("/%i", (i << 1) >> 1);
33  if (i >> 31) ret += '\'';
34  }
35  return ret;
36 }
37 
39 struct PubkeyProvider
40 {
41  virtual ~PubkeyProvider() = default;
42 
44  virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const = 0;
45 
47  virtual bool IsRange() const = 0;
48 
50  virtual size_t GetSize() const = 0;
51 
53  virtual std::string ToString() const = 0;
54 
56  virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
57 };
58 
59 class OriginPubkeyProvider final : public PubkeyProvider
60 {
61  KeyOriginInfo m_origin;
62  std::unique_ptr<PubkeyProvider> m_provider;
63 
64  std::string OriginString() const
65  {
66  return HexStr(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint)) + FormatKeyPath(m_origin.path);
67  }
68 
69 public:
70  OriginPubkeyProvider(KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : m_origin(std::move(info)), m_provider(std::move(provider)) {}
71  bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
72  {
73  if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
74  std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
75  info.path.insert(info.path.begin(), m_origin.path.begin(), m_origin.path.end());
76  return true;
77  }
78  bool IsRange() const override { return m_provider->IsRange(); }
79  size_t GetSize() const override { return m_provider->GetSize(); }
80  std::string ToString() const override { return "[" + OriginString() + "]" + m_provider->ToString(); }
81  bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
82  {
83  std::string sub;
84  if (!m_provider->ToPrivateString(arg, sub)) return false;
85  ret = "[" + OriginString() + "]" + std::move(sub);
86  return true;
87  }
88 };
89 
91 class ConstPubkeyProvider final : public PubkeyProvider
92 {
93  CPubKey m_pubkey;
94 
95 public:
96  ConstPubkeyProvider(const CPubKey& pubkey) : m_pubkey(pubkey) {}
97  bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
98  {
99  key = m_pubkey;
100  info.path.clear();
101  CKeyID keyid = m_pubkey.GetID();
102  std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
103  return true;
104  }
105  bool IsRange() const override { return false; }
106  size_t GetSize() const override { return m_pubkey.size(); }
107  std::string ToString() const override { return HexStr(m_pubkey.begin(), m_pubkey.end()); }
108  bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
109  {
110  CKey key;
111  if (!arg.GetKey(m_pubkey.GetID(), key)) return false;
112  ret = EncodeSecret(key);
113  return true;
114  }
115 };
116 
117 enum class DeriveType {
118  NO,
119  UNHARDENED,
120  HARDENED,
121 };
122 
124 class BIP32PubkeyProvider final : public PubkeyProvider
125 {
126  CExtPubKey m_extkey;
127  KeyPath m_path;
128  DeriveType m_derive;
129 
130  bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const
131  {
132  CKey key;
133  if (!arg.GetKey(m_extkey.pubkey.GetID(), key)) return false;
134  ret.nDepth = m_extkey.nDepth;
135  std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
136  ret.nChild = m_extkey.nChild;
137  ret.chaincode = m_extkey.chaincode;
138  ret.key = key;
139  return true;
140  }
141 
142  bool IsHardened() const
143  {
144  if (m_derive == DeriveType::HARDENED) return true;
145  for (auto entry : m_path) {
146  if (entry >> 31) return true;
147  }
148  return false;
149  }
150 
151 public:
152  BIP32PubkeyProvider(const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
153  bool IsRange() const override { return m_derive != DeriveType::NO; }
154  size_t GetSize() const override { return 33; }
155  bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
156  {
157  if (IsHardened()) {
158  CExtKey extkey;
159  if (!GetExtKey(arg, extkey)) return false;
160  for (auto entry : m_path) {
161  extkey.Derive(extkey, entry);
162  }
163  if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
164  if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
165  key = extkey.Neuter().pubkey;
166  } else {
167  // TODO: optimize by caching
168  CExtPubKey extkey = m_extkey;
169  for (auto entry : m_path) {
170  extkey.Derive(extkey, entry);
171  }
172  if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
173  assert(m_derive != DeriveType::HARDENED);
174  key = extkey.pubkey;
175  }
176  CKeyID keyid = m_extkey.pubkey.GetID();
177  std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
178  info.path = m_path;
179  if (m_derive == DeriveType::UNHARDENED) info.path.push_back((uint32_t)pos);
180  if (m_derive == DeriveType::HARDENED) info.path.push_back(((uint32_t)pos) | 0x80000000L);
181  return true;
182  }
183  std::string ToString() const override
184  {
185  std::string ret = EncodeExtPubKey(m_extkey) + FormatKeyPath(m_path);
186  if (IsRange()) {
187  ret += "/*";
188  if (m_derive == DeriveType::HARDENED) ret += '\'';
189  }
190  return ret;
191  }
192  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
193  {
194  CExtKey key;
195  if (!GetExtKey(arg, key)) return false;
196  out = EncodeExtKey(key) + FormatKeyPath(m_path);
197  if (IsRange()) {
198  out += "/*";
199  if (m_derive == DeriveType::HARDENED) out += '\'';
200  }
201  return true;
202  }
203 };
204 
206 class AddressDescriptor final : public Descriptor
207 {
208  CTxDestination m_destination;
209 
210 public:
211  AddressDescriptor(CTxDestination destination) : m_destination(std::move(destination)) {}
212 
213  bool IsRange() const override { return false; }
214  std::string ToString() const override { return "addr(" + EncodeDestination(m_destination) + ")"; }
215  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override { out = ToString(); return true; }
216  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
217  {
218  output_scripts = std::vector<CScript>{GetScriptForDestination(m_destination)};
219  return true;
220  }
221 };
222 
224 class RawDescriptor final : public Descriptor
225 {
226  CScript m_script;
227 
228 public:
229  RawDescriptor(CScript script) : m_script(std::move(script)) {}
230 
231  bool IsRange() const override { return false; }
232  std::string ToString() const override { return "raw(" + HexStr(m_script.begin(), m_script.end()) + ")"; }
233  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override { out = ToString(); return true; }
234  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
235  {
236  output_scripts = std::vector<CScript>{m_script};
237  return true;
238  }
239 };
240 
242 class SingleKeyDescriptor final : public Descriptor
243 {
244  const std::function<CScript(const CPubKey&)> m_script_fn;
245  const std::string m_fn_name;
246  std::unique_ptr<PubkeyProvider> m_provider;
247 
248 public:
249  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)) {}
250 
251  bool IsRange() const override { return m_provider->IsRange(); }
252  std::string ToString() const override { return m_fn_name + "(" + m_provider->ToString() + ")"; }
253  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
254  {
255  std::string ret;
256  if (!m_provider->ToPrivateString(arg, ret)) return false;
257  out = m_fn_name + "(" + std::move(ret) + ")";
258  return true;
259  }
260  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
261  {
262  CPubKey key;
263  KeyOriginInfo info;
264  if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
265  output_scripts = std::vector<CScript>{m_script_fn(key)};
266  out.origins.emplace(key.GetID(), std::move(info));
267  out.pubkeys.emplace(key.GetID(), key);
268  return true;
269  }
270 };
271 
272 CScript P2PKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(pubkey.GetID()); }
273 CScript P2PKGetScript(const CPubKey& pubkey) { return GetScriptForRawPubKey(pubkey); }
274 CScript P2WPKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(WitnessV0KeyHash(pubkey.GetID())); }
275 
277 class MultisigDescriptor : public Descriptor
278 {
279  int m_threshold;
280  std::vector<std::unique_ptr<PubkeyProvider>> m_providers;
281 
282 public:
283  MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers) : m_threshold(threshold), m_providers(std::move(providers)) {}
284 
285  bool IsRange() const override
286  {
287  for (const auto& p : m_providers) {
288  if (p->IsRange()) return true;
289  }
290  return false;
291  }
292 
293  std::string ToString() const override
294  {
295  std::string ret = strprintf("multi(%i", m_threshold);
296  for (const auto& p : m_providers) {
297  ret += "," + p->ToString();
298  }
299  return std::move(ret) + ")";
300  }
301 
302  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
303  {
304  std::string ret = strprintf("multi(%i", m_threshold);
305  for (const auto& p : m_providers) {
306  std::string sub;
307  if (!p->ToPrivateString(arg, sub)) return false;
308  ret += "," + std::move(sub);
309  }
310  out = std::move(ret) + ")";
311  return true;
312  }
313 
314  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
315  {
316  std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
317  entries.reserve(m_providers.size());
318  // Construct temporary data in `entries`, to avoid producing output in case of failure.
319  for (const auto& p : m_providers) {
320  entries.emplace_back();
321  if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second)) return false;
322  }
323  std::vector<CPubKey> pubkeys;
324  pubkeys.reserve(entries.size());
325  for (auto& entry : entries) {
326  pubkeys.push_back(entry.first);
327  out.origins.emplace(entry.first.GetID(), std::move(entry.second));
328  out.pubkeys.emplace(entry.first.GetID(), entry.first);
329  }
330  output_scripts = std::vector<CScript>{GetScriptForMultisig(m_threshold, pubkeys)};
331  return true;
332  }
333 };
334 
336 class ConvertorDescriptor : public Descriptor
337 {
338  const std::function<CScript(const CScript&)> m_convert_fn;
339  const std::string m_fn_name;
340  std::unique_ptr<Descriptor> m_descriptor;
341 
342 public:
343  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)) {}
344 
345  bool IsRange() const override { return m_descriptor->IsRange(); }
346  std::string ToString() const override { return m_fn_name + "(" + m_descriptor->ToString() + ")"; }
347  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
348  {
349  std::string ret;
350  if (!m_descriptor->ToPrivateString(arg, ret)) return false;
351  out = m_fn_name + "(" + std::move(ret) + ")";
352  return true;
353  }
354  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
355  {
356  std::vector<CScript> sub;
357  if (!m_descriptor->Expand(pos, arg, sub, out)) return false;
358  output_scripts.clear();
359  for (const auto& script : sub) {
360  CScriptID id(script);
361  out.scripts.emplace(CScriptID(script), script);
362  output_scripts.push_back(m_convert_fn(script));
363  }
364  return true;
365  }
366 };
367 
368 CScript ConvertP2SH(const CScript& script) { return GetScriptForDestination(CScriptID(script)); }
369 CScript ConvertP2WSH(const CScript& script) { return GetScriptForDestination(WitnessV0ScriptHash(script)); }
370 
372 class ComboDescriptor final : public Descriptor
373 {
374  std::unique_ptr<PubkeyProvider> m_provider;
375 
376 public:
377  ComboDescriptor(std::unique_ptr<PubkeyProvider> provider) : m_provider(std::move(provider)) {}
378 
379  bool IsRange() const override { return m_provider->IsRange(); }
380  std::string ToString() const override { return "combo(" + m_provider->ToString() + ")"; }
381  bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
382  {
383  std::string ret;
384  if (!m_provider->ToPrivateString(arg, ret)) return false;
385  out = "combo(" + std::move(ret) + ")";
386  return true;
387  }
388  bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
389  {
390  CPubKey key;
391  KeyOriginInfo info;
392  if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
393  CKeyID keyid = key.GetID();
394  {
395  CScript p2pk = GetScriptForRawPubKey(key);
396  CScript p2pkh = GetScriptForDestination(keyid);
397  output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)};
398  out.pubkeys.emplace(keyid, key);
399  out.origins.emplace(keyid, std::move(info));
400  }
401  if (key.IsCompressed()) {
403  CScriptID p2wpkh_id(p2wpkh);
404  CScript p2sh_p2wpkh = GetScriptForDestination(p2wpkh_id);
405  out.scripts.emplace(p2wpkh_id, p2wpkh);
406  output_scripts.push_back(std::move(p2wpkh));
407  output_scripts.push_back(std::move(p2sh_p2wpkh));
408  }
409  return true;
410  }
411 };
412 
414 // Parser //
416 
417 enum class ParseScriptContext {
418  TOP,
419  P2SH,
420  P2WSH,
421 };
422 
424 bool Const(const std::string& str, Span<const char>& sp)
425 {
426  if ((size_t)sp.size() >= str.size() && std::equal(str.begin(), str.end(), sp.begin())) {
427  sp = sp.subspan(str.size());
428  return true;
429  }
430  return false;
431 }
432 
434 bool Func(const std::string& str, Span<const char>& sp)
435 {
436  if ((size_t)sp.size() >= str.size() + 2 && sp[str.size()] == '(' && sp[sp.size() - 1] == ')' && std::equal(str.begin(), str.end(), sp.begin())) {
437  sp = sp.subspan(str.size() + 1, sp.size() - str.size() - 2);
438  return true;
439  }
440  return false;
441 }
442 
445 {
446  int level = 0;
447  auto it = sp.begin();
448  while (it != sp.end()) {
449  if (*it == '(') {
450  ++level;
451  } else if (level && *it == ')') {
452  --level;
453  } else if (level == 0 && (*it == ')' || *it == ',')) {
454  break;
455  }
456  ++it;
457  }
458  Span<const char> ret = sp.first(it - sp.begin());
459  sp = sp.subspan(it - sp.begin());
460  return ret;
461 }
462 
464 std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
465 {
466  std::vector<Span<const char>> ret;
467  auto it = sp.begin();
468  auto start = it;
469  while (it != sp.end()) {
470  if (*it == sep) {
471  ret.emplace_back(start, it);
472  start = it + 1;
473  }
474  ++it;
475  }
476  ret.emplace_back(start, it);
477  return ret;
478 }
479 
481 bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
482 {
483  for (size_t i = 1; i < split.size(); ++i) {
484  Span<const char> elem = split[i];
485  bool hardened = false;
486  if (elem.size() > 0 && (elem[elem.size() - 1] == '\'' || elem[elem.size() - 1] == 'h')) {
487  elem = elem.first(elem.size() - 1);
488  hardened = true;
489  }
490  uint32_t p;
491  if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p) || p > 0x7FFFFFFFUL) return false;
492  out.push_back(p | (((uint32_t)hardened) << 31));
493  }
494  return true;
495 }
496 
498 std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out)
499 {
500  auto split = Split(sp, '/');
501  std::string str(split[0].begin(), split[0].end());
502  if (split.size() == 1) {
503  if (IsHex(str)) {
504  std::vector<unsigned char> data = ParseHex(str);
505  CPubKey pubkey(data);
506  if (pubkey.IsFullyValid() && (permit_uncompressed || pubkey.IsCompressed())) return MakeUnique<ConstPubkeyProvider>(pubkey);
507  }
508  CKey key = DecodeSecret(str);
509  if (key.IsValid() && (permit_uncompressed || key.IsCompressed())) {
510  CPubKey pubkey = key.GetPubKey();
511  out.keys.emplace(pubkey.GetID(), key);
512  return MakeUnique<ConstPubkeyProvider>(pubkey);
513  }
514  }
515  CExtKey extkey = DecodeExtKey(str);
516  CExtPubKey extpubkey = DecodeExtPubKey(str);
517  if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) return nullptr;
518  KeyPath path;
519  DeriveType type = DeriveType::NO;
520  if (split.back() == MakeSpan("*").first(1)) {
521  split.pop_back();
522  type = DeriveType::UNHARDENED;
523  } else if (split.back() == MakeSpan("*'").first(2) || split.back() == MakeSpan("*h").first(2)) {
524  split.pop_back();
525  type = DeriveType::HARDENED;
526  }
527  if (!ParseKeyPath(split, path)) return nullptr;
528  if (extkey.key.IsValid()) {
529  extpubkey = extkey.Neuter();
530  out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
531  }
532  return MakeUnique<BIP32PubkeyProvider>(extpubkey, std::move(path), type);
533 }
534 
536 std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out)
537 {
538  auto origin_split = Split(sp, ']');
539  if (origin_split.size() > 2) return nullptr;
540  if (origin_split.size() == 1) return ParsePubkeyInner(origin_split[0], permit_uncompressed, out);
541  if (origin_split[0].size() < 1 || origin_split[0][0] != '[') return nullptr;
542  auto slash_split = Split(origin_split[0].subspan(1), '/');
543  if (slash_split[0].size() != 8) return nullptr;
544  std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].end());
545  if (!IsHex(fpr_hex)) return nullptr;
546  auto fpr_bytes = ParseHex(fpr_hex);
547  KeyOriginInfo info;
548  static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");
549  assert(fpr_bytes.size() == 4);
550  std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
551  if (!ParseKeyPath(slash_split, info.path)) return nullptr;
552  auto provider = ParsePubkeyInner(origin_split[1], permit_uncompressed, out);
553  if (!provider) return nullptr;
554  return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(provider));
555 }
556 
558 std::unique_ptr<Descriptor> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out)
559 {
560  auto expr = Expr(sp);
561  if (Func("pk", expr)) {
562  auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out);
563  if (!pubkey) return nullptr;
564  return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKGetScript, "pk");
565  }
566  if (Func("pkh", expr)) {
567  auto pubkey = ParsePubkey(expr, ctx != ParseScriptContext::P2WSH, out);
568  if (!pubkey) return nullptr;
569  return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2PKHGetScript, "pkh");
570  }
571  if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
572  auto pubkey = ParsePubkey(expr, true, out);
573  if (!pubkey) return nullptr;
574  return MakeUnique<ComboDescriptor>(std::move(pubkey));
575  }
576  if (Func("multi", expr)) {
577  auto threshold = Expr(expr);
578  uint32_t thres;
579  std::vector<std::unique_ptr<PubkeyProvider>> providers;
580  if (!ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres)) return nullptr;
581  size_t script_size = 0;
582  while (expr.size()) {
583  if (!Const(",", expr)) return nullptr;
584  auto arg = Expr(expr);
585  auto pk = ParsePubkey(arg, ctx != ParseScriptContext::P2WSH, out);
586  if (!pk) return nullptr;
587  script_size += pk->GetSize() + 1;
588  providers.emplace_back(std::move(pk));
589  }
590  if (providers.size() < 1 || providers.size() > 16 || thres < 1 || thres > providers.size()) return nullptr;
591  if (ctx == ParseScriptContext::TOP) {
592  if (providers.size() > 3) return nullptr; // Not more than 3 pubkeys for raw multisig
593  }
594  if (ctx == ParseScriptContext::P2SH) {
595  if (script_size + 3 > 520) return nullptr; // Enforce P2SH script size limit
596  }
597  return MakeUnique<MultisigDescriptor>(thres, std::move(providers));
598  }
599  if (ctx != ParseScriptContext::P2WSH && Func("wpkh", expr)) {
600  auto pubkey = ParsePubkey(expr, false, out);
601  if (!pubkey) return nullptr;
602  return MakeUnique<SingleKeyDescriptor>(std::move(pubkey), P2WPKHGetScript, "wpkh");
603  }
604  if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
605  auto desc = ParseScript(expr, ParseScriptContext::P2SH, out);
606  if (!desc || expr.size()) return nullptr;
607  return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2SH, "sh");
608  }
609  if (ctx != ParseScriptContext::P2WSH && Func("wsh", expr)) {
610  auto desc = ParseScript(expr, ParseScriptContext::P2WSH, out);
611  if (!desc || expr.size()) return nullptr;
612  return MakeUnique<ConvertorDescriptor>(std::move(desc), ConvertP2WSH, "wsh");
613  }
614  if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {
615  CTxDestination dest = DecodeDestination(std::string(expr.begin(), expr.end()));
616  if (!IsValidDestination(dest)) return nullptr;
617  return MakeUnique<AddressDescriptor>(std::move(dest));
618  }
619  if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
620  std::string str(expr.begin(), expr.end());
621  if (!IsHex(str)) return nullptr;
622  auto bytes = ParseHex(str);
623  return MakeUnique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
624  }
625  return nullptr;
626 }
627 
628 } // namespace
629 
630 std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out)
631 {
632  Span<const char> sp(descriptor.data(), descriptor.size());
633  auto ret = ParseScript(sp, ParseScriptContext::TOP, out);
634  if (sp.size() == 0 && ret) return ret;
635  return nullptr;
636 }
constexpr std::ptrdiff_t size() const noexcept
Definition: span.h:30
unsigned char fingerprint[4]
Definition: sign.h:25
constexpr C * end() const noexcept
Definition: span.h:29
CKey key
Definition: key.h:146
bool Derive(CExtKey &out, unsigned int nChild) const
Definition: key.cpp:288
DeriveType
Definition: descriptor.cpp:117
#define strprintf
Definition: tinyformat.h:1066
auto start
Definition: rpcwallet.cpp:1067
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out)
Parse a descriptor string.
Definition: descriptor.cpp:630
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:179
std::map< CKeyID, CKey > keys
Definition: sign.h:62
CExtKey DecodeExtKey(const std::string &str)
Definition: key_io.cpp:185
UniValue ret(UniValue::VARR)
Definition: rpcwallet.cpp:1140
Definition: key.h:141
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:324
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: standard.cpp:296
std::map< CKeyID, KeyOriginInfo > origins
Definition: sign.h:61
constexpr Span< A > MakeSpan(A(&a)[N])
Create a span to a container exposing data() and size().
Definition: span.h:55
unsigned char * begin()
Definition: uint256.h:56
CExtPubKey DecodeExtPubKey(const std::string &str)
Definition: key_io.cpp:162
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:155
virtual std::string ToString() const =0
Convert the descriptor back to a string, undoing parsing.
constexpr Span< C > subspan(std::ptrdiff_t offset) const noexcept
Definition: span.h:33
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid()) ...
Definition: pubkey.cpp:206
std::map< CScriptID, CScript > scripts
Definition: sign.h:59
boost::variant< CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:123
const char * name
Definition: rest.cpp:37
bool IsValid() const
Definition: pubkey.h:171
An encapsulated public key.
Definition: pubkey.h:30
std::map< CKeyID, CPubKey > pubkeys
Definition: sign.h:60
bool IsHex(const std::string &str)
ParseScriptContext
Definition: descriptor.cpp:417
auto end
Definition: rpcwallet.cpp:1068
constexpr Span< C > first(std::ptrdiff_t count) const noexcept
Definition: span.h:35
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:96
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:288
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 GetKey(const CKeyID &address, CKey &key) const
Definition: sign.h:36
constexpr C * begin() const noexcept
Definition: span.h:28
CTxDestination DecodeDestination(const std::string &str)
Definition: key_io.cpp:214
bool Derive(CExtPubKey &out, unsigned int nChild) const
Definition: pubkey.cpp:266
std::string EncodeExtPubKey(const CExtPubKey &key)
Definition: key_io.cpp:175
An interface to be implemented by keystores that support signing.
Definition: sign.h:30
CExtPubKey Neuter() const
Definition: key.cpp:307
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:384
A reference to a CKey: the Hash360 of its serialized public key.
Definition: pubkey.h:20
bool ParseUInt32(const std::string &str, uint32_t *out)
Convert decimal string to unsigned 32-bit integer with strict parse error feedback.
A reference to a CScript: the Hash360 of its serialization (see script.h)
Definition: standard.h:22
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:209
CPubKey pubkey
Definition: pubkey.h:211
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
Definition: standard.cpp:301
An encapsulated private key.
Definition: key.h:27
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:17
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:133
virtual bool IsRange() const =0
Whether the expansion of this descriptor depends on the position.
CScript ParseScript(const std::string &s)
Definition: core_read.cpp:24
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:149
std::vector< uint32_t > path
Definition: sign.h:26
virtual bool ToPrivateString(const SigningProvider &provider, std::string &out) const =0
Convert the descriptor to a private string.
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:198
Interface for parsed descriptor objects.
Definition: descriptor.h:29
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
std::vector< unsigned char > ParseHex(const char *psz)
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180