Branch data Line data Source code
# 1 : : // Copyright (c) 2018-2022 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/bip32.h>
# 14 : : #include <util/spanparsing.h>
# 15 : : #include <util/system.h>
# 16 : : #include <util/strencodings.h>
# 17 : : #include <util/vector.h>
# 18 : :
# 19 : : #include <memory>
# 20 : : #include <optional>
# 21 : : #include <string>
# 22 : : #include <vector>
# 23 : :
# 24 : : namespace {
# 25 : :
# 26 : : ////////////////////////////////////////////////////////////////////////////
# 27 : : // Checksum //
# 28 : : ////////////////////////////////////////////////////////////////////////////
# 29 : :
# 30 : : // This section implements a checksum algorithm for descriptors with the
# 31 : : // following properties:
# 32 : : // * Mistakes in a descriptor string are measured in "symbol errors". The higher
# 33 : : // the number of symbol errors, the harder it is to detect:
# 34 : : // * An error substituting a character from 0123456789()[],'/*abcdefgh@:$%{} for
# 35 : : // another in that set always counts as 1 symbol error.
# 36 : : // * Note that hex encoded keys are covered by these characters. Xprvs and
# 37 : : // xpubs use other characters too, but already have their own checksum
# 38 : : // mechanism.
# 39 : : // * Function names like "multi()" use other characters, but mistakes in
# 40 : : // these would generally result in an unparsable descriptor.
# 41 : : // * A case error always counts as 1 symbol error.
# 42 : : // * Any other 1 character substitution error counts as 1 or 2 symbol errors.
# 43 : : // * Any 1 symbol error is always detected.
# 44 : : // * Any 2 or 3 symbol error in a descriptor of up to 49154 characters is always detected.
# 45 : : // * Any 4 symbol error in a descriptor of up to 507 characters is always detected.
# 46 : : // * Any 5 symbol error in a descriptor of up to 77 characters is always detected.
# 47 : : // * Is optimized to minimize the chance a 5 symbol error in a descriptor up to 387 characters is undetected
# 48 : : // * Random errors have a chance of 1 in 2**40 of being undetected.
# 49 : : //
# 50 : : // These properties are achieved by expanding every group of 3 (non checksum) characters into
# 51 : : // 4 GF(32) symbols, over which a cyclic code is defined.
# 52 : :
# 53 : : /*
# 54 : : * Interprets c as 8 groups of 5 bits which are the coefficients of a degree 8 polynomial over GF(32),
# 55 : : * multiplies that polynomial by x, computes its remainder modulo a generator, and adds the constant term val.
# 56 : : *
# 57 : : * This generator is G(x) = x^8 + {30}x^7 + {23}x^6 + {15}x^5 + {14}x^4 + {10}x^3 + {6}x^2 + {12}x + {9}.
# 58 : : * It is chosen to define an cyclic error detecting code which is selected by:
# 59 : : * - Starting from all BCH codes over GF(32) of degree 8 and below, which by construction guarantee detecting
# 60 : : * 3 errors in windows up to 19000 symbols.
# 61 : : * - Taking all those generators, and for degree 7 ones, extend them to degree 8 by adding all degree-1 factors.
# 62 : : * - Selecting just the set of generators that guarantee detecting 4 errors in a window of length 512.
# 63 : : * - Selecting one of those with best worst-case behavior for 5 errors in windows of length up to 512.
# 64 : : *
# 65 : : * The generator and the constants to implement it can be verified using this Sage code:
# 66 : : * B = GF(2) # Binary field
# 67 : : * BP.<b> = B[] # Polynomials over the binary field
# 68 : : * F_mod = b**5 + b**3 + 1
# 69 : : * F.<f> = GF(32, modulus=F_mod, repr='int') # GF(32) definition
# 70 : : * FP.<x> = F[] # Polynomials over GF(32)
# 71 : : * E_mod = x**3 + x + F.fetch_int(8)
# 72 : : * E.<e> = F.extension(E_mod) # Extension field definition
# 73 : : * alpha = e**2743 # Choice of an element in extension field
# 74 : : * for p in divisors(E.order() - 1): # Verify alpha has order 32767.
# 75 : : * assert((alpha**p == 1) == (p % 32767 == 0))
# 76 : : * G = lcm([(alpha**i).minpoly() for i in [1056,1057,1058]] + [x + 1])
# 77 : : * print(G) # Print out the generator
# 78 : : * for i in [1,2,4,8,16]: # Print out {1,2,4,8,16}*(G mod x^8), packed in hex integers.
# 79 : : * v = 0
# 80 : : * for coef in reversed((F.fetch_int(i)*(G % x**8)).coefficients(sparse=True)):
# 81 : : * v = v*32 + coef.integer_representation()
# 82 : : * print("0x%x" % v)
# 83 : : */
# 84 : : uint64_t PolyMod(uint64_t c, int val)
# 85 : 147193151 : {
# 86 : 147193151 : uint8_t c0 = c >> 35;
# 87 : 147193151 : c = ((c & 0x7ffffffff) << 5) ^ val;
# 88 [ + + ]: 147193151 : if (c0 & 1) c ^= 0xf5dee51989;
# 89 [ + + ]: 147193151 : if (c0 & 2) c ^= 0xa9fdca3312;
# 90 [ + + ]: 147193151 : if (c0 & 4) c ^= 0x1bab10e32d;
# 91 [ + + ]: 147193151 : if (c0 & 8) c ^= 0x3706b1677a;
# 92 [ + + ]: 147193151 : if (c0 & 16) c ^= 0x644d626ffd;
# 93 : 147193151 : return c;
# 94 : 147193151 : }
# 95 : :
# 96 : : std::string DescriptorChecksum(const Span<const char>& span)
# 97 : 306616 : {
# 98 : : /** A character set designed such that:
# 99 : : * - The most common 'unprotected' descriptor characters (hex, keypaths) are in the first group of 32.
# 100 : : * - Case errors cause an offset that's a multiple of 32.
# 101 : : * - As many alphabetic characters are in the same group (while following the above restrictions).
# 102 : : *
# 103 : : * If p(x) gives the position of a character c in this character set, every group of 3 characters
# 104 : : * (a,b,c) is encoded as the 4 symbols (p(a) & 31, p(b) & 31, p(c) & 31, (p(a) / 32) + 3 * (p(b) / 32) + 9 * (p(c) / 32).
# 105 : : * This means that changes that only affect the lower 5 bits of the position, or only the higher 2 bits, will just
# 106 : : * affect a single symbol.
# 107 : : *
# 108 : : * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect
# 109 : : * the position within the groups.
# 110 : : */
# 111 : 306616 : static std::string INPUT_CHARSET =
# 112 : 306616 : "0123456789()[],'/*abcdefgh@:$%{}"
# 113 : 306616 : "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~"
# 114 : 306616 : "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
# 115 : :
# 116 : : /** The character set for the checksum itself (same as bech32). */
# 117 : 306616 : static std::string CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
# 118 : :
# 119 : 306616 : uint64_t c = 1;
# 120 : 306616 : int cls = 0;
# 121 : 306616 : int clscount = 0;
# 122 [ + + ]: 108474608 : for (auto ch : span) {
# 123 : 108474608 : auto pos = INPUT_CHARSET.find(ch);
# 124 [ + + ]: 108474608 : if (pos == std::string::npos) return "";
# 125 : 108474606 : c = PolyMod(c, pos & 31); // Emit a symbol for the position inside the group, for every character.
# 126 : 108474606 : cls = cls * 3 + (pos >> 5); // Accumulate the group numbers
# 127 [ + + ]: 108474606 : if (++clscount == 3) {
# 128 : : // Emit an extra symbol representing the group numbers, for every 3 characters.
# 129 : 36024572 : c = PolyMod(c, cls);
# 130 : 36024572 : cls = 0;
# 131 : 36024572 : clscount = 0;
# 132 : 36024572 : }
# 133 : 108474606 : }
# 134 [ + + ]: 306614 : if (clscount > 0) c = PolyMod(c, cls);
# 135 [ + + ]: 2759526 : for (int j = 0; j < 8; ++j) c = PolyMod(c, 0); // Shift further to determine the checksum.
# 136 : 306614 : c ^= 1; // Prevent appending zeroes from not affecting the checksum.
# 137 : :
# 138 : 306614 : std::string ret(8, ' ');
# 139 [ + + ]: 2759526 : for (int j = 0; j < 8; ++j) ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31];
# 140 : 306614 : return ret;
# 141 : 306616 : }
# 142 : :
# 143 : 301598 : std::string AddChecksum(const std::string& str) { return str + "#" + DescriptorChecksum(str); }
# 144 : :
# 145 : : ////////////////////////////////////////////////////////////////////////////
# 146 : : // Internal representation //
# 147 : : ////////////////////////////////////////////////////////////////////////////
# 148 : :
# 149 : : typedef std::vector<uint32_t> KeyPath;
# 150 : :
# 151 : : /** Interface for public key objects in descriptors. */
# 152 : : struct PubkeyProvider
# 153 : : {
# 154 : : protected:
# 155 : : //! Index of this key expression in the descriptor
# 156 : : //! E.g. If this PubkeyProvider is key1 in multi(2, key1, key2, key3), then m_expr_index = 0
# 157 : : uint32_t m_expr_index;
# 158 : :
# 159 : : public:
# 160 : 388005 : explicit PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {}
# 161 : :
# 162 : 388005 : virtual ~PubkeyProvider() = default;
# 163 : :
# 164 : : /** Derive a public key.
# 165 : : * read_cache is the cache to read keys from (if not nullptr)
# 166 : : * write_cache is the cache to write keys to (if not nullptr)
# 167 : : * Caches are not exclusive but this is not tested. Currently we use them exclusively
# 168 : : */
# 169 : : virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const = 0;
# 170 : :
# 171 : : /** Whether this represent multiple public keys at different positions. */
# 172 : : virtual bool IsRange() const = 0;
# 173 : :
# 174 : : /** Get the size of the generated public key(s) in bytes (33 or 65). */
# 175 : : virtual size_t GetSize() const = 0;
# 176 : :
# 177 : : /** Get the descriptor string form. */
# 178 : : virtual std::string ToString() const = 0;
# 179 : :
# 180 : : /** Get the descriptor string form including private data (if available in arg). */
# 181 : : virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
# 182 : :
# 183 : : /** Get the descriptor string form with the xpub at the last hardened derivation */
# 184 : : virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
# 185 : :
# 186 : : /** Derive a private key, if private data is available in arg. */
# 187 : : virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
# 188 : : };
# 189 : :
# 190 : : class OriginPubkeyProvider final : public PubkeyProvider
# 191 : : {
# 192 : : KeyOriginInfo m_origin;
# 193 : : std::unique_ptr<PubkeyProvider> m_provider;
# 194 : :
# 195 : : std::string OriginString() const
# 196 : 106411 : {
# 197 : 106411 : return HexStr(m_origin.fingerprint) + FormatHDKeypath(m_origin.path);
# 198 : 106411 : }
# 199 : :
# 200 : : public:
# 201 : 183496 : OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
# 202 : : bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
# 203 : 105750 : {
# 204 [ + + ]: 105750 : if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
# 205 : 105717 : std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
# 206 : 105717 : info.path.insert(info.path.begin(), m_origin.path.begin(), m_origin.path.end());
# 207 : 105717 : return true;
# 208 : 105750 : }
# 209 : 9694 : bool IsRange() const override { return m_provider->IsRange(); }
# 210 : 4380 : size_t GetSize() const override { return m_provider->GetSize(); }
# 211 : 106193 : std::string ToString() const override { return "[" + OriginString() + "]" + m_provider->ToString(); }
# 212 : : bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
# 213 : 200 : {
# 214 : 200 : std::string sub;
# 215 [ + + ]: 200 : if (!m_provider->ToPrivateString(arg, sub)) return false;
# 216 : 100 : ret = "[" + OriginString() + "]" + std::move(sub);
# 217 : 100 : return true;
# 218 : 200 : }
# 219 : : bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
# 220 : 118 : {
# 221 : 118 : std::string sub;
# 222 [ - + ]: 118 : if (!m_provider->ToNormalizedString(arg, sub, cache)) return false;
# 223 : : // If m_provider is a BIP32PubkeyProvider, we may get a string formatted like a OriginPubkeyProvider
# 224 : : // In that case, we need to strip out the leading square bracket and fingerprint from the substring,
# 225 : : // and append that to our own origin string.
# 226 [ + + ]: 118 : if (sub[0] == '[') {
# 227 : 16 : sub = sub.substr(9);
# 228 : 16 : ret = "[" + OriginString() + std::move(sub);
# 229 : 102 : } else {
# 230 : 102 : ret = "[" + OriginString() + "]" + std::move(sub);
# 231 : 102 : }
# 232 : 118 : return true;
# 233 : 118 : }
# 234 : : bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
# 235 : 94 : {
# 236 : 94 : return m_provider->GetPrivKey(pos, arg, key);
# 237 : 94 : }
# 238 : : };
# 239 : :
# 240 : : /** An object representing a parsed constant public key in a descriptor. */
# 241 : : class ConstPubkeyProvider final : public PubkeyProvider
# 242 : : {
# 243 : : CPubKey m_pubkey;
# 244 : : bool m_xonly;
# 245 : :
# 246 : : public:
# 247 : 201003 : ConstPubkeyProvider(uint32_t exp_index, const CPubKey& pubkey, bool xonly) : PubkeyProvider(exp_index), m_pubkey(pubkey), m_xonly(xonly) {}
# 248 : : bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
# 249 : 1224077 : {
# 250 : 1224077 : key = m_pubkey;
# 251 : 1224077 : info.path.clear();
# 252 : 1224077 : CKeyID keyid = m_pubkey.GetID();
# 253 : 1224077 : std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
# 254 : 1224077 : return true;
# 255 : 1224077 : }
# 256 : 19251 : bool IsRange() const override { return false; }
# 257 : 20784 : size_t GetSize() const override { return m_pubkey.size(); }
# 258 [ + + ]: 989890 : std::string ToString() const override { return m_xonly ? HexStr(m_pubkey).substr(2) : HexStr(m_pubkey); }
# 259 : : bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
# 260 : 436 : {
# 261 : 436 : CKey key;
# 262 [ + + ]: 436 : if (m_xonly) {
# 263 [ + + ]: 40 : for (const auto& keyid : XOnlyPubKey(m_pubkey).GetKeyIDs()) {
# 264 : 40 : arg.GetKey(keyid, key);
# 265 [ + + ]: 40 : if (key.IsValid()) break;
# 266 : 40 : }
# 267 : 416 : } else {
# 268 : 416 : arg.GetKey(m_pubkey.GetID(), key);
# 269 : 416 : }
# 270 [ + + ]: 436 : if (!key.IsValid()) return false;
# 271 : 336 : ret = EncodeSecret(key);
# 272 : 336 : return true;
# 273 : 436 : }
# 274 : : bool ToNormalizedString(const SigningProvider& arg, std::string& ret, const DescriptorCache* cache) const override
# 275 : 4468 : {
# 276 : 4468 : ret = ToString();
# 277 : 4468 : return true;
# 278 : 4468 : }
# 279 : : bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
# 280 : 27973 : {
# 281 : 27973 : return arg.GetKey(m_pubkey.GetID(), key);
# 282 : 27973 : }
# 283 : : };
# 284 : :
# 285 : : enum class DeriveType {
# 286 : : NO,
# 287 : : UNHARDENED,
# 288 : : HARDENED,
# 289 : : };
# 290 : :
# 291 : : /** An object representing a parsed extended public key in a descriptor. */
# 292 : : class BIP32PubkeyProvider final : public PubkeyProvider
# 293 : : {
# 294 : : // Root xpub, path, and final derivation step type being used, if any
# 295 : : CExtPubKey m_root_extkey;
# 296 : : KeyPath m_path;
# 297 : : DeriveType m_derive;
# 298 : :
# 299 : : bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const
# 300 : 18907 : {
# 301 : 18907 : CKey key;
# 302 [ + + ]: 18907 : if (!arg.GetKey(m_root_extkey.pubkey.GetID(), key)) return false;
# 303 : 17687 : ret.nDepth = m_root_extkey.nDepth;
# 304 : 17687 : std::copy(m_root_extkey.vchFingerprint, m_root_extkey.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
# 305 : 17687 : ret.nChild = m_root_extkey.nChild;
# 306 : 17687 : ret.chaincode = m_root_extkey.chaincode;
# 307 : 17687 : ret.key = key;
# 308 : 17687 : return true;
# 309 : 18907 : }
# 310 : :
# 311 : : // Derives the last xprv
# 312 : : bool GetDerivedExtKey(const SigningProvider& arg, CExtKey& xprv, CExtKey& last_hardened) const
# 313 : 18504 : {
# 314 [ + + ]: 18504 : if (!GetExtKey(arg, xprv)) return false;
# 315 [ + + ]: 40546 : for (auto entry : m_path) {
# 316 : 40546 : xprv.Derive(xprv, entry);
# 317 [ + + ]: 40546 : if (entry >> 31) {
# 318 : 30003 : last_hardened = xprv;
# 319 : 30003 : }
# 320 : 40546 : }
# 321 : 17441 : return true;
# 322 : 18504 : }
# 323 : :
# 324 : : bool IsHardened() const
# 325 : 24079 : {
# 326 [ + + ]: 24079 : if (m_derive == DeriveType::HARDENED) return true;
# 327 [ + + ]: 22227 : for (auto entry : m_path) {
# 328 [ + + ]: 22227 : if (entry >> 31) return true;
# 329 : 22227 : }
# 330 : 9735 : return false;
# 331 : 15871 : }
# 332 : :
# 333 : : public:
# 334 : 3506 : BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
# 335 : 242718 : bool IsRange() const override { return m_derive != DeriveType::NO; }
# 336 : 586 : size_t GetSize() const override { return 33; }
# 337 : : bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
# 338 : 577685 : {
# 339 : : // Info of parent of the to be derived pubkey
# 340 : 577685 : KeyOriginInfo parent_info;
# 341 : 577685 : CKeyID keyid = m_root_extkey.pubkey.GetID();
# 342 : 577685 : std::copy(keyid.begin(), keyid.begin() + sizeof(parent_info.fingerprint), parent_info.fingerprint);
# 343 : 577685 : parent_info.path = m_path;
# 344 : :
# 345 : : // Info of the derived key itself which is copied out upon successful completion
# 346 : 577685 : KeyOriginInfo final_info_out_tmp = parent_info;
# 347 [ + + ]: 577685 : if (m_derive == DeriveType::UNHARDENED) final_info_out_tmp.path.push_back((uint32_t)pos);
# 348 [ + + ]: 577685 : if (m_derive == DeriveType::HARDENED) final_info_out_tmp.path.push_back(((uint32_t)pos) | 0x80000000L);
# 349 : :
# 350 : : // Derive keys or fetch them from cache
# 351 : 577685 : CExtPubKey final_extkey = m_root_extkey;
# 352 : 577685 : CExtPubKey parent_extkey = m_root_extkey;
# 353 : 577685 : CExtPubKey last_hardened_extkey;
# 354 : 577685 : bool der = true;
# 355 [ + + ]: 577685 : if (read_cache) {
# 356 [ + + ]: 553606 : if (!read_cache->GetCachedDerivedExtPubKey(m_expr_index, pos, final_extkey)) {
# 357 [ + + ]: 552870 : if (m_derive == DeriveType::HARDENED) return false;
# 358 : : // Try to get the derivation parent
# 359 [ + + ]: 550772 : if (!read_cache->GetCachedParentExtPubKey(m_expr_index, parent_extkey)) return false;
# 360 : 549188 : final_extkey = parent_extkey;
# 361 [ + + ]: 549188 : if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
# 362 : 549188 : }
# 363 [ + + ]: 553606 : } else if (IsHardened()) {
# 364 : 14344 : CExtKey xprv;
# 365 : 14344 : CExtKey lh_xprv;
# 366 [ + + ]: 14344 : if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return false;
# 367 : 14126 : parent_extkey = xprv.Neuter();
# 368 [ + + ]: 14126 : if (m_derive == DeriveType::UNHARDENED) der = xprv.Derive(xprv, pos);
# 369 [ + + ]: 14126 : if (m_derive == DeriveType::HARDENED) der = xprv.Derive(xprv, pos | 0x80000000UL);
# 370 : 14126 : final_extkey = xprv.Neuter();
# 371 [ + + ]: 14126 : if (lh_xprv.key.IsValid()) {
# 372 : 11029 : last_hardened_extkey = lh_xprv.Neuter();
# 373 : 11029 : }
# 374 : 14126 : } else {
# 375 [ + + ]: 16085 : for (auto entry : m_path) {
# 376 : 16085 : der = parent_extkey.Derive(parent_extkey, entry);
# 377 : 16085 : assert(der);
# 378 : 16085 : }
# 379 : 9735 : final_extkey = parent_extkey;
# 380 [ + + ]: 9735 : if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
# 381 : 9735 : assert(m_derive != DeriveType::HARDENED);
# 382 : 9735 : }
# 383 : 573785 : assert(der);
# 384 : :
# 385 : 0 : final_info_out = final_info_out_tmp;
# 386 : 573785 : key_out = final_extkey.pubkey;
# 387 : :
# 388 [ + + ]: 573785 : if (write_cache) {
# 389 : : // Only cache parent if there is any unhardened derivation
# 390 [ + + ]: 4547 : if (m_derive != DeriveType::HARDENED) {
# 391 : 2575 : write_cache->CacheParentExtPubKey(m_expr_index, parent_extkey);
# 392 : : // Cache last hardened xpub if we have it
# 393 [ + + ]: 2575 : if (last_hardened_extkey.pubkey.IsValid()) {
# 394 : 1509 : write_cache->CacheLastHardenedExtPubKey(m_expr_index, last_hardened_extkey);
# 395 : 1509 : }
# 396 [ + - ]: 2575 : } else if (final_info_out.path.size() > 0) {
# 397 : 1972 : write_cache->CacheDerivedExtPubKey(m_expr_index, pos, final_extkey);
# 398 : 1972 : }
# 399 : 4547 : }
# 400 : :
# 401 : 573785 : return true;
# 402 : 577685 : }
# 403 : : std::string ToString() const override
# 404 : 190106 : {
# 405 : 190106 : std::string ret = EncodeExtPubKey(m_root_extkey) + FormatHDKeypath(m_path);
# 406 [ + + ]: 190106 : if (IsRange()) {
# 407 : 189795 : ret += "/*";
# 408 [ + + ]: 189795 : if (m_derive == DeriveType::HARDENED) ret += '\'';
# 409 : 189795 : }
# 410 : 190106 : return ret;
# 411 : 190106 : }
# 412 : : bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
# 413 : 403 : {
# 414 : 403 : CExtKey key;
# 415 [ + + ]: 403 : if (!GetExtKey(arg, key)) return false;
# 416 : 246 : out = EncodeExtKey(key) + FormatHDKeypath(m_path);
# 417 [ + + ]: 246 : if (IsRange()) {
# 418 : 90 : out += "/*";
# 419 [ + + ]: 90 : if (m_derive == DeriveType::HARDENED) out += '\'';
# 420 : 90 : }
# 421 : 246 : return true;
# 422 : 403 : }
# 423 : : bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
# 424 : 759 : {
# 425 : : // For hardened derivation type, just return the typical string, nothing to normalize
# 426 [ + + ]: 759 : if (m_derive == DeriveType::HARDENED) {
# 427 : 34 : out = ToString();
# 428 : 34 : return true;
# 429 : 34 : }
# 430 : : // Step backwards to find the last hardened step in the path
# 431 : 725 : int i = (int)m_path.size() - 1;
# 432 [ + + ]: 1251 : for (; i >= 0; --i) {
# 433 [ + + ]: 901 : if (m_path.at(i) >> 31) {
# 434 : 375 : break;
# 435 : 375 : }
# 436 : 901 : }
# 437 : : // Either no derivation or all unhardened derivation
# 438 [ + + ]: 725 : if (i == -1) {
# 439 : 350 : out = ToString();
# 440 : 350 : return true;
# 441 : 350 : }
# 442 : : // Get the path to the last hardened stup
# 443 : 375 : KeyOriginInfo origin;
# 444 : 375 : int k = 0;
# 445 [ + + ]: 1404 : for (; k <= i; ++k) {
# 446 : : // Add to the path
# 447 : 1029 : origin.path.push_back(m_path.at(k));
# 448 : 1029 : }
# 449 : : // Build the remaining path
# 450 : 375 : KeyPath end_path;
# 451 [ + + ]: 750 : for (; k < (int)m_path.size(); ++k) {
# 452 : 375 : end_path.push_back(m_path.at(k));
# 453 : 375 : }
# 454 : : // Get the fingerprint
# 455 : 375 : CKeyID id = m_root_extkey.pubkey.GetID();
# 456 : 375 : std::copy(id.begin(), id.begin() + 4, origin.fingerprint);
# 457 : :
# 458 : 375 : CExtPubKey xpub;
# 459 : 375 : CExtKey lh_xprv;
# 460 : : // If we have the cache, just get the parent xpub
# 461 [ + + ]: 375 : if (cache != nullptr) {
# 462 : 327 : cache->GetCachedLastHardenedExtPubKey(m_expr_index, xpub);
# 463 : 327 : }
# 464 [ + + ]: 375 : if (!xpub.pubkey.IsValid()) {
# 465 : : // Cache miss, or nor cache, or need privkey
# 466 : 48 : CExtKey xprv;
# 467 [ - + ]: 48 : if (!GetDerivedExtKey(arg, xprv, lh_xprv)) return false;
# 468 : 48 : xpub = lh_xprv.Neuter();
# 469 : 48 : }
# 470 : 375 : assert(xpub.pubkey.IsValid());
# 471 : :
# 472 : : // Build the string
# 473 : 0 : std::string origin_str = HexStr(origin.fingerprint) + FormatHDKeypath(origin.path);
# 474 : 375 : out = "[" + origin_str + "]" + EncodeExtPubKey(xpub) + FormatHDKeypath(end_path);
# 475 [ + + ]: 375 : if (IsRange()) {
# 476 : 327 : out += "/*";
# 477 : 327 : assert(m_derive == DeriveType::UNHARDENED);
# 478 : 327 : }
# 479 : 0 : return true;
# 480 : 375 : }
# 481 : : bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
# 482 : 4112 : {
# 483 : 4112 : CExtKey extkey;
# 484 : 4112 : CExtKey dummy;
# 485 [ + + ]: 4112 : if (!GetDerivedExtKey(arg, extkey, dummy)) return false;
# 486 [ + + ]: 3267 : if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
# 487 [ + + ]: 3267 : if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
# 488 : 3267 : key = extkey.key;
# 489 : 3267 : return true;
# 490 : 4112 : }
# 491 : : };
# 492 : :
# 493 : : /** Base class for all Descriptor implementations. */
# 494 : : class DescriptorImpl : public Descriptor
# 495 : : {
# 496 : : //! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for Multisig).
# 497 : : const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args;
# 498 : : //! The string name of the descriptor function.
# 499 : : const std::string m_name;
# 500 : :
# 501 : : protected:
# 502 : : //! The sub-descriptor arguments (empty for everything but SH and WSH).
# 503 : : //! In doc/descriptors.m this is referred to as SCRIPT expressions sh(SCRIPT)
# 504 : : //! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.
# 505 : : //! Subdescriptors can only ever generate a single script.
# 506 : : const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;
# 507 : :
# 508 : : //! Return a serialization of anything except pubkey and script arguments, to be prepended to those.
# 509 : 350284 : virtual std::string ToStringExtra() const { return ""; }
# 510 : :
# 511 : : /** A helper function to construct the scripts for this descriptor.
# 512 : : *
# 513 : : * This function is invoked once by ExpandHelper.
# 514 : : *
# 515 : : * @param pubkeys The evaluations of the m_pubkey_args field.
# 516 : : * @param scripts The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).
# 517 : : * @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
# 518 : : * The origin info of the provided pubkeys is automatically added.
# 519 : : * @return A vector with scriptPubKeys for this descriptor.
# 520 : : */
# 521 : : virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, Span<const CScript> scripts, FlatSigningProvider& out) const = 0;
# 522 : :
# 523 : : public:
# 524 : 203156 : DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}
# 525 : 29629 : 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))) {}
# 526 : 1006 : DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, std::vector<std::unique_ptr<DescriptorImpl>> scripts, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args(std::move(scripts)) {}
# 527 : :
# 528 : : enum class StringType
# 529 : : {
# 530 : : PUBLIC,
# 531 : : PRIVATE,
# 532 : : NORMALIZED,
# 533 : : };
# 534 : :
# 535 : : bool IsSolvable() const override
# 536 : 4191 : {
# 537 [ + + ]: 4191 : for (const auto& arg : m_subdescriptor_args) {
# 538 [ - + ]: 1589 : if (!arg->IsSolvable()) return false;
# 539 : 1589 : }
# 540 : 4191 : return true;
# 541 : 4191 : }
# 542 : :
# 543 : : bool IsRange() const final
# 544 : 68393 : {
# 545 [ + + ]: 71242 : for (const auto& pubkey : m_pubkey_args) {
# 546 [ + + ]: 71242 : if (pubkey->IsRange()) return true;
# 547 : 71242 : }
# 548 [ + + ]: 16617 : for (const auto& arg : m_subdescriptor_args) {
# 549 [ + + ]: 8194 : if (arg->IsRange()) return true;
# 550 : 8194 : }
# 551 : 9767 : return false;
# 552 : 16617 : }
# 553 : :
# 554 : : virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const
# 555 : 364879 : {
# 556 : 364879 : size_t pos = 0;
# 557 [ + + ]: 364879 : for (const auto& scriptarg : m_subdescriptor_args) {
# 558 [ - + ]: 38363 : if (pos++) ret += ",";
# 559 : 38363 : std::string tmp;
# 560 [ + + ]: 38363 : if (!scriptarg->ToStringHelper(arg, tmp, type, cache)) return false;
# 561 : 38223 : ret += std::move(tmp);
# 562 : 38223 : }
# 563 : 364739 : return true;
# 564 : 364879 : }
# 565 : :
# 566 : : bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr) const
# 567 : 393995 : {
# 568 : 393995 : std::string extra = ToStringExtra();
# 569 [ + + ]: 393995 : size_t pos = extra.size() > 0 ? 1 : 0;
# 570 : 393995 : std::string ret = m_name + "(" + extra;
# 571 [ + + ]: 1181210 : for (const auto& pubkey : m_pubkey_args) {
# 572 [ + + ]: 1181210 : if (pos++) ret += ",";
# 573 : 1181210 : std::string tmp;
# 574 [ - + ]: 1181210 : switch (type) {
# 575 [ + + ]: 5227 : case StringType::NORMALIZED:
# 576 [ - + ]: 5227 : if (!pubkey->ToNormalizedString(*arg, tmp, cache)) return false;
# 577 : 5227 : break;
# 578 [ + + ]: 5227 : case StringType::PRIVATE:
# 579 [ + + ]: 839 : if (!pubkey->ToPrivateString(*arg, tmp)) return false;
# 580 : 582 : break;
# 581 [ + + ]: 1175144 : case StringType::PUBLIC:
# 582 : 1175144 : tmp = pubkey->ToString();
# 583 : 1175144 : break;
# 584 : 1181210 : }
# 585 : 1180953 : ret += std::move(tmp);
# 586 : 1180953 : }
# 587 : 393738 : std::string subscript;
# 588 [ + + ]: 393738 : if (!ToStringSubScriptHelper(arg, subscript, type, cache)) return false;
# 589 [ + + ][ + + ]: 393598 : if (pos && subscript.size()) ret += ',';
# 590 : 393598 : out = std::move(ret) + std::move(subscript) + ")";
# 591 : 393598 : return true;
# 592 : 393738 : }
# 593 : :
# 594 : : std::string ToString() const final
# 595 : 300375 : {
# 596 : 300375 : std::string ret;
# 597 : 300375 : ToStringHelper(nullptr, ret, StringType::PUBLIC);
# 598 : 300375 : return AddChecksum(ret);
# 599 : 300375 : }
# 600 : :
# 601 : : bool ToPrivateString(const SigningProvider& arg, std::string& out) const final
# 602 : 515 : {
# 603 : 515 : bool ret = ToStringHelper(&arg, out, StringType::PRIVATE);
# 604 : 515 : out = AddChecksum(out);
# 605 : 515 : return ret;
# 606 : 515 : }
# 607 : :
# 608 : : bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override final
# 609 : 708 : {
# 610 : 708 : bool ret = ToStringHelper(&arg, out, StringType::NORMALIZED, cache);
# 611 : 708 : out = AddChecksum(out);
# 612 : 708 : return ret;
# 613 : 708 : }
# 614 : :
# 615 : : bool ExpandHelper(int pos, const SigningProvider& arg, const DescriptorCache* read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache) const
# 616 : 703972 : {
# 617 : 703972 : std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
# 618 : 703972 : entries.reserve(m_pubkey_args.size());
# 619 : :
# 620 : : // Construct temporary data in `entries`, `subscripts`, and `subprovider` to avoid producing output in case of failure.
# 621 [ + + ]: 1801762 : for (const auto& p : m_pubkey_args) {
# 622 : 1801762 : entries.emplace_back();
# 623 [ + + ]: 1801762 : if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second, read_cache, write_cache)) return false;
# 624 : 1801762 : }
# 625 : 700072 : std::vector<CScript> subscripts;
# 626 : 700072 : FlatSigningProvider subprovider;
# 627 [ + + ]: 700072 : for (const auto& subarg : m_subdescriptor_args) {
# 628 : 114800 : std::vector<CScript> outscripts;
# 629 [ + + ]: 114800 : if (!subarg->ExpandHelper(pos, arg, read_cache, outscripts, subprovider, write_cache)) return false;
# 630 : 114052 : assert(outscripts.size() == 1);
# 631 : 0 : subscripts.emplace_back(std::move(outscripts[0]));
# 632 : 114052 : }
# 633 : 699324 : out = Merge(std::move(out), std::move(subprovider));
# 634 : :
# 635 : 699324 : std::vector<CPubKey> pubkeys;
# 636 : 699324 : pubkeys.reserve(entries.size());
# 637 [ + + ]: 1797796 : for (auto& entry : entries) {
# 638 : 1797796 : pubkeys.push_back(entry.first);
# 639 : 1797796 : out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
# 640 : 1797796 : }
# 641 : :
# 642 : 699324 : output_scripts = MakeScripts(pubkeys, Span{subscripts}, out);
# 643 : 699324 : return true;
# 644 : 700072 : }
# 645 : :
# 646 : : bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const final
# 647 : 97729 : {
# 648 : 97729 : return ExpandHelper(pos, provider, nullptr, output_scripts, out, write_cache);
# 649 : 97729 : }
# 650 : :
# 651 : : bool ExpandFromCache(int pos, const DescriptorCache& read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const final
# 652 : 491443 : {
# 653 : 491443 : return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &read_cache, output_scripts, out, nullptr);
# 654 : 491443 : }
# 655 : :
# 656 : : void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
# 657 : 8924 : {
# 658 [ + + ]: 32085 : for (const auto& p : m_pubkey_args) {
# 659 : 32085 : CKey key;
# 660 [ + + ]: 32085 : if (!p->GetPrivKey(pos, provider, key)) continue;
# 661 : 7736 : out.keys.emplace(key.GetPubKey().GetID(), key);
# 662 : 7736 : }
# 663 [ + + ]: 8924 : for (const auto& arg : m_subdescriptor_args) {
# 664 : 1096 : arg->ExpandPrivate(pos, provider, out);
# 665 : 1096 : }
# 666 : 8924 : }
# 667 : :
# 668 : 227 : std::optional<OutputType> GetOutputType() const override { return std::nullopt; }
# 669 : : };
# 670 : :
# 671 : : /** A parsed addr(A) descriptor. */
# 672 : : class AddressDescriptor final : public DescriptorImpl
# 673 : : {
# 674 : : const CTxDestination m_destination;
# 675 : : protected:
# 676 : 11810 : std::string ToStringExtra() const override { return EncodeDestination(m_destination); }
# 677 : 668 : std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(GetScriptForDestination(m_destination)); }
# 678 : : public:
# 679 : 12324 : AddressDescriptor(CTxDestination destination) : DescriptorImpl({}, "addr"), m_destination(std::move(destination)) {}
# 680 : 18 : bool IsSolvable() const final { return false; }
# 681 : :
# 682 : : std::optional<OutputType> GetOutputType() const override
# 683 : 20 : {
# 684 : 20 : return OutputTypeFromDestination(m_destination);
# 685 : 20 : }
# 686 : 0 : bool IsSingleType() const final { return true; }
# 687 : : };
# 688 : :
# 689 : : /** A parsed raw(H) descriptor. */
# 690 : : class RawDescriptor final : public DescriptorImpl
# 691 : : {
# 692 : : const CScript m_script;
# 693 : : protected:
# 694 : 15140 : std::string ToStringExtra() const override { return HexStr(m_script); }
# 695 : 520 : std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript>, FlatSigningProvider&) const override { return Vector(m_script); }
# 696 : : public:
# 697 : 15472 : RawDescriptor(CScript script) : DescriptorImpl({}, "raw"), m_script(std::move(script)) {}
# 698 : 0 : bool IsSolvable() const final { return false; }
# 699 : :
# 700 : : std::optional<OutputType> GetOutputType() const override
# 701 : 2 : {
# 702 : 2 : CTxDestination dest;
# 703 : 2 : ExtractDestination(m_script, dest);
# 704 : 2 : return OutputTypeFromDestination(dest);
# 705 : 2 : }
# 706 : 0 : bool IsSingleType() const final { return true; }
# 707 : : };
# 708 : :
# 709 : : /** A parsed pk(P) descriptor. */
# 710 : : class PKDescriptor final : public DescriptorImpl
# 711 : : {
# 712 : : private:
# 713 : : const bool m_xonly;
# 714 : : protected:
# 715 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override
# 716 : 33178 : {
# 717 [ + + ]: 33178 : if (m_xonly) {
# 718 : 30631 : CScript script = CScript() << ToByteVector(XOnlyPubKey(keys[0])) << OP_CHECKSIG;
# 719 : 30631 : return Vector(std::move(script));
# 720 : 30631 : } else {
# 721 : 2547 : return Vector(GetScriptForRawPubKey(keys[0]));
# 722 : 2547 : }
# 723 : 33178 : }
# 724 : : public:
# 725 : 23157 : PKDescriptor(std::unique_ptr<PubkeyProvider> prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {}
# 726 : 1 : bool IsSingleType() const final { return true; }
# 727 : : };
# 728 : :
# 729 : : /** A parsed pkh(P) descriptor. */
# 730 : : class PKHDescriptor final : public DescriptorImpl
# 731 : : {
# 732 : : protected:
# 733 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
# 734 : 72365 : {
# 735 : 72365 : CKeyID id = keys[0].GetID();
# 736 : 72365 : out.pubkeys.emplace(id, keys[0]);
# 737 : 72365 : return Vector(GetScriptForDestination(PKHash(id)));
# 738 : 72365 : }
# 739 : : public:
# 740 : 54543 : PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
# 741 : 836 : std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
# 742 : 4390 : bool IsSingleType() const final { return true; }
# 743 : : };
# 744 : :
# 745 : : /** A parsed wpkh(P) descriptor. */
# 746 : : class WPKHDescriptor final : public DescriptorImpl
# 747 : : {
# 748 : : protected:
# 749 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
# 750 : 348633 : {
# 751 : 348633 : CKeyID id = keys[0].GetID();
# 752 : 348633 : out.pubkeys.emplace(id, keys[0]);
# 753 : 348633 : return Vector(GetScriptForDestination(WitnessV0KeyHash(id)));
# 754 : 348633 : }
# 755 : : public:
# 756 : 93993 : WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
# 757 : 10988 : std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
# 758 : 10296 : bool IsSingleType() const final { return true; }
# 759 : : };
# 760 : :
# 761 : : /** A parsed combo(P) descriptor. */
# 762 : : class ComboDescriptor final : public DescriptorImpl
# 763 : : {
# 764 : : protected:
# 765 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider& out) const override
# 766 : 75014 : {
# 767 : 75014 : std::vector<CScript> ret;
# 768 : 75014 : CKeyID id = keys[0].GetID();
# 769 : 75014 : out.pubkeys.emplace(id, keys[0]);
# 770 : 75014 : ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK
# 771 : 75014 : ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH
# 772 [ + + ]: 75014 : if (keys[0].IsCompressed()) {
# 773 : 74965 : CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(id));
# 774 : 74965 : out.scripts.emplace(CScriptID(p2wpkh), p2wpkh);
# 775 : 74965 : ret.emplace_back(p2wpkh);
# 776 : 74965 : ret.emplace_back(GetScriptForDestination(ScriptHash(p2wpkh))); // P2SH-P2WPKH
# 777 : 74965 : }
# 778 : 75014 : return ret;
# 779 : 75014 : }
# 780 : : public:
# 781 : 241 : ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
# 782 : 1 : bool IsSingleType() const final { return false; }
# 783 : : };
# 784 : :
# 785 : : /** A parsed multi(...) or sortedmulti(...) descriptor */
# 786 : : class MultisigDescriptor final : public DescriptorImpl
# 787 : : {
# 788 : : const int m_threshold;
# 789 : : const bool m_sorted;
# 790 : : protected:
# 791 : 9141 : std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
# 792 : 24257 : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
# 793 [ + + ]: 24257 : if (m_sorted) {
# 794 : 2953 : std::vector<CPubKey> sorted_keys(keys);
# 795 : 2953 : std::sort(sorted_keys.begin(), sorted_keys.end());
# 796 : 2953 : return Vector(GetScriptForMultisig(m_threshold, sorted_keys));
# 797 : 2953 : }
# 798 : 21304 : return Vector(GetScriptForMultisig(m_threshold, keys));
# 799 : 24257 : }
# 800 : : public:
# 801 : 3258 : 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) {}
# 802 : 0 : bool IsSingleType() const final { return true; }
# 803 : : };
# 804 : :
# 805 : : /** A parsed (sorted)multi_a(...) descriptor. Always uses x-only pubkeys. */
# 806 : : class MultiADescriptor final : public DescriptorImpl
# 807 : : {
# 808 : : const int m_threshold;
# 809 : : const bool m_sorted;
# 810 : : protected:
# 811 : 7620 : std::string ToStringExtra() const override { return strprintf("%i", m_threshold); }
# 812 : 7403 : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
# 813 : 7403 : CScript ret;
# 814 : 7403 : std::vector<XOnlyPubKey> xkeys;
# 815 [ + + ]: 1080719 : for (const auto& key : keys) xkeys.emplace_back(key);
# 816 [ + + ]: 7403 : if (m_sorted) std::sort(xkeys.begin(), xkeys.end());
# 817 : 7403 : ret << ToByteVector(xkeys[0]) << OP_CHECKSIG;
# 818 [ + + ]: 1080719 : for (size_t i = 1; i < keys.size(); ++i) {
# 819 : 1073316 : ret << ToByteVector(xkeys[i]) << OP_CHECKSIGADD;
# 820 : 1073316 : }
# 821 : 7403 : ret << m_threshold << OP_NUMEQUAL;
# 822 : 7403 : return Vector(std::move(ret));
# 823 : 7403 : }
# 824 : : public:
# 825 : 168 : MultiADescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti_a" : "multi_a"), m_threshold(threshold), m_sorted(sorted) {}
# 826 : 0 : bool IsSingleType() const final { return true; }
# 827 : : };
# 828 : :
# 829 : : /** A parsed sh(...) descriptor. */
# 830 : : class SHDescriptor final : public DescriptorImpl
# 831 : : {
# 832 : : protected:
# 833 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
# 834 : 54420 : {
# 835 : 54420 : auto ret = Vector(GetScriptForDestination(ScriptHash(scripts[0])));
# 836 [ + - ]: 54420 : if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
# 837 : 54420 : return ret;
# 838 : 54420 : }
# 839 : : public:
# 840 : 26649 : SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
# 841 : :
# 842 : : std::optional<OutputType> GetOutputType() const override
# 843 : 681 : {
# 844 : 681 : assert(m_subdescriptor_args.size() == 1);
# 845 [ + + ]: 681 : if (m_subdescriptor_args[0]->GetOutputType() == OutputType::BECH32) return OutputType::P2SH_SEGWIT;
# 846 : 84 : return OutputType::LEGACY;
# 847 : 681 : }
# 848 : 515 : bool IsSingleType() const final { return true; }
# 849 : : };
# 850 : :
# 851 : : /** A parsed wsh(...) descriptor. */
# 852 : : class WSHDescriptor final : public DescriptorImpl
# 853 : : {
# 854 : : protected:
# 855 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, Span<const CScript> scripts, FlatSigningProvider& out) const override
# 856 : 21598 : {
# 857 : 21598 : auto ret = Vector(GetScriptForDestination(WitnessV0ScriptHash(scripts[0])));
# 858 [ + - ]: 21598 : if (ret.size()) out.scripts.emplace(CScriptID(scripts[0]), scripts[0]);
# 859 : 21598 : return ret;
# 860 : 21598 : }
# 861 : : public:
# 862 : 2980 : WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
# 863 : 703 : std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
# 864 : 778 : bool IsSingleType() const final { return true; }
# 865 : : };
# 866 : :
# 867 : : /** A parsed tr(...) descriptor. */
# 868 : : class TRDescriptor final : public DescriptorImpl
# 869 : : {
# 870 : : std::vector<int> m_depths;
# 871 : : protected:
# 872 : : std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript> scripts, FlatSigningProvider& out) const override
# 873 : 61268 : {
# 874 : 61268 : TaprootBuilder builder;
# 875 : 61268 : assert(m_depths.size() == scripts.size());
# 876 [ + + ]: 99291 : for (size_t pos = 0; pos < m_depths.size(); ++pos) {
# 877 : 38023 : builder.Add(m_depths[pos], scripts[pos], TAPROOT_LEAF_TAPSCRIPT);
# 878 : 38023 : }
# 879 [ - + ]: 61268 : if (!builder.IsComplete()) return {};
# 880 : 61268 : assert(keys.size() == 1);
# 881 : 0 : XOnlyPubKey xpk(keys[0]);
# 882 [ - + ]: 61268 : if (!xpk.IsFullyValid()) return {};
# 883 : 61268 : builder.Finalize(xpk);
# 884 : 61268 : WitnessV1Taproot output = builder.GetOutput();
# 885 : 61268 : out.tr_spenddata[output].Merge(builder.GetSpendData());
# 886 : 61268 : out.pubkeys.emplace(keys[0].GetID(), keys[0]);
# 887 : 61268 : return Vector(GetScriptForDestination(output));
# 888 : 61268 : }
# 889 : : bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
# 890 : 28859 : {
# 891 [ + + ]: 28859 : if (m_depths.empty()) return true;
# 892 : 21008 : std::vector<bool> path;
# 893 [ + + ]: 75042 : for (size_t pos = 0; pos < m_depths.size(); ++pos) {
# 894 [ + + ]: 54034 : if (pos) ret += ',';
# 895 [ + + ]: 108068 : while ((int)path.size() <= m_depths[pos]) {
# 896 [ + + ]: 54034 : if (path.size()) ret += '{';
# 897 : 54034 : path.push_back(false);
# 898 : 54034 : }
# 899 : 54034 : std::string tmp;
# 900 [ - + ]: 54034 : if (!m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, type, cache)) return false;
# 901 : 54034 : ret += std::move(tmp);
# 902 [ + - ][ + + ]: 87060 : while (!path.empty() && path.back()) {
# [ + + ]
# 903 [ + - ]: 33026 : if (path.size() > 1) ret += '}';
# 904 : 33026 : path.pop_back();
# 905 : 33026 : }
# 906 [ + - ]: 54034 : if (!path.empty()) path.back() = true;
# 907 : 54034 : }
# 908 : 21008 : return true;
# 909 : 21008 : }
# 910 : : public:
# 911 : : TRDescriptor(std::unique_ptr<PubkeyProvider> internal_key, std::vector<std::unique_ptr<DescriptorImpl>> descs, std::vector<int> depths) :
# 912 : : DescriptorImpl(Vector(std::move(internal_key)), std::move(descs), "tr"), m_depths(std::move(depths))
# 913 : 1006 : {
# 914 : 1006 : assert(m_subdescriptor_args.size() == m_depths.size());
# 915 : 1006 : }
# 916 : 815 : std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
# 917 : 604 : bool IsSingleType() const final { return true; }
# 918 : : };
# 919 : :
# 920 : : ////////////////////////////////////////////////////////////////////////////
# 921 : : // Parser //
# 922 : : ////////////////////////////////////////////////////////////////////////////
# 923 : :
# 924 : : enum class ParseScriptContext {
# 925 : : TOP, //!< Top-level context (script goes directly in scriptPubKey)
# 926 : : P2SH, //!< Inside sh() (script becomes P2SH redeemScript)
# 927 : : P2WPKH, //!< Inside wpkh() (no script, pubkey only)
# 928 : : P2WSH, //!< Inside wsh() (script becomes v0 witness script)
# 929 : : P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf)
# 930 : : };
# 931 : :
# 932 : : /** Parse a key path, being passed a split list of elements (the first element is ignored). */
# 933 : : [[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
# 934 : 8459 : {
# 935 [ + + ]: 20940 : for (size_t i = 1; i < split.size(); ++i) {
# 936 : 12489 : Span<const char> elem = split[i];
# 937 : 12489 : bool hardened = false;
# 938 [ + - ][ + + ]: 12489 : if (elem.size() > 0 && (elem[elem.size() - 1] == '\'' || elem[elem.size() - 1] == 'h')) {
# [ + + ]
# 939 : 9072 : elem = elem.first(elem.size() - 1);
# 940 : 9072 : hardened = true;
# 941 : 9072 : }
# 942 : 12489 : uint32_t p;
# 943 [ + + ]: 12489 : if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p)) {
# 944 : 4 : error = strprintf("Key path value '%s' is not a valid uint32", std::string(elem.begin(), elem.end()));
# 945 : 4 : return false;
# 946 [ + + ]: 12485 : } else if (p > 0x7FFFFFFFUL) {
# 947 : 4 : error = strprintf("Key path value %u is out of range", p);
# 948 : 4 : return false;
# 949 : 4 : }
# 950 : 12481 : out.push_back(p | (((uint32_t)hardened) << 31));
# 951 : 12481 : }
# 952 : 8451 : return true;
# 953 : 8459 : }
# 954 : :
# 955 : : /** Parse a public key that excludes origin information. */
# 956 : : std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
# 957 : 25478 : {
# 958 : 25478 : using namespace spanparsing;
# 959 : :
# 960 [ + + ][ + + ]: 25478 : bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH;
# 961 : 25478 : auto split = Split(sp, '/');
# 962 : 25478 : std::string str(split[0].begin(), split[0].end());
# 963 [ + + ]: 25478 : if (str.size() == 0) {
# 964 : 4 : error = "No key provided";
# 965 : 4 : return nullptr;
# 966 : 4 : }
# 967 [ + + ]: 25474 : if (split.size() == 1) {
# 968 [ + + ]: 22015 : if (IsHex(str)) {
# 969 : 21516 : std::vector<unsigned char> data = ParseHex(str);
# 970 : 21516 : CPubKey pubkey(data);
# 971 [ + + ]: 21516 : if (pubkey.IsFullyValid()) {
# 972 [ + + ][ + + ]: 966 : if (permit_uncompressed || pubkey.IsCompressed()) {
# 973 : 960 : return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false);
# 974 : 960 : } else {
# 975 : 6 : error = "Uncompressed keys are not allowed";
# 976 : 6 : return nullptr;
# 977 : 6 : }
# 978 [ + - ][ + + ]: 20550 : } else if (data.size() == 32 && ctx == ParseScriptContext::P2TR) {
# 979 : 20548 : unsigned char fullkey[33] = {0x02};
# 980 : 20548 : std::copy(data.begin(), data.end(), fullkey + 1);
# 981 : 20548 : pubkey.Set(std::begin(fullkey), std::end(fullkey));
# 982 [ + - ]: 20548 : if (pubkey.IsFullyValid()) {
# 983 : 20548 : return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, true);
# 984 : 20548 : }
# 985 : 20548 : }
# 986 : 2 : error = strprintf("Pubkey '%s' is invalid", str);
# 987 : 2 : return nullptr;
# 988 : 21516 : }
# 989 : 499 : CKey key = DecodeSecret(str);
# 990 [ + + ]: 499 : if (key.IsValid()) {
# 991 [ + + ][ + + ]: 442 : if (permit_uncompressed || key.IsCompressed()) {
# 992 : 436 : CPubKey pubkey = key.GetPubKey();
# 993 : 436 : out.keys.emplace(pubkey.GetID(), key);
# 994 : 436 : return std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR);
# 995 : 436 : } else {
# 996 : 6 : error = "Uncompressed keys are not allowed";
# 997 : 6 : return nullptr;
# 998 : 6 : }
# 999 : 442 : }
# 1000 : 499 : }
# 1001 : 3516 : CExtKey extkey = DecodeExtKey(str);
# 1002 : 3516 : CExtPubKey extpubkey = DecodeExtPubKey(str);
# 1003 [ + + ][ + + ]: 3516 : if (!extkey.key.IsValid() && !extpubkey.pubkey.IsValid()) {
# 1004 : 2 : error = strprintf("key '%s' is not valid", str);
# 1005 : 2 : return nullptr;
# 1006 : 2 : }
# 1007 : 3514 : KeyPath path;
# 1008 : 3514 : DeriveType type = DeriveType::NO;
# 1009 [ + + ]: 3514 : if (split.back() == Span{"*"}.first(1)) {
# 1010 : 3242 : split.pop_back();
# 1011 : 3242 : type = DeriveType::UNHARDENED;
# 1012 [ + + ][ + + ]: 3242 : } else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) {
# [ + + ]
# 1013 : 68 : split.pop_back();
# 1014 : 68 : type = DeriveType::HARDENED;
# 1015 : 68 : }
# 1016 [ + + ]: 3514 : if (!ParseKeyPath(split, path, error)) return nullptr;
# 1017 [ + + ]: 3506 : if (extkey.key.IsValid()) {
# 1018 : 501 : extpubkey = extkey.Neuter();
# 1019 : 501 : out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
# 1020 : 501 : }
# 1021 : 3506 : return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
# 1022 : 3514 : }
# 1023 : :
# 1024 : : /** Parse a public key including origin information (if enabled). */
# 1025 : : std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
# 1026 : 25506 : {
# 1027 : 25506 : using namespace spanparsing;
# 1028 : :
# 1029 : 25506 : auto origin_split = Split(sp, ']');
# 1030 [ + + ]: 25506 : if (origin_split.size() > 2) {
# 1031 : 8 : error = "Multiple ']' characters found for a single pubkey";
# 1032 : 8 : return nullptr;
# 1033 : 8 : }
# 1034 [ + + ]: 25498 : if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error);
# 1035 [ - + ][ + + ]: 4965 : if (origin_split[0].empty() || origin_split[0][0] != '[') {
# 1036 : 4 : error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",
# 1037 [ - + ]: 4 : origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);
# 1038 : 4 : return nullptr;
# 1039 : 4 : }
# 1040 : 4961 : auto slash_split = Split(origin_split[0].subspan(1), '/');
# 1041 [ + + ]: 4961 : if (slash_split[0].size() != 8) {
# 1042 : 12 : error = strprintf("Fingerprint is not 4 bytes (%u characters instead of 8 characters)", slash_split[0].size());
# 1043 : 12 : return nullptr;
# 1044 : 12 : }
# 1045 : 4949 : std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].end());
# 1046 [ + + ]: 4949 : if (!IsHex(fpr_hex)) {
# 1047 : 4 : error = strprintf("Fingerprint '%s' is not hex", fpr_hex);
# 1048 : 4 : return nullptr;
# 1049 : 4 : }
# 1050 : 4945 : auto fpr_bytes = ParseHex(fpr_hex);
# 1051 : 4945 : KeyOriginInfo info;
# 1052 : 4945 : static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");
# 1053 : 4945 : assert(fpr_bytes.size() == 4);
# 1054 : 0 : std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
# 1055 [ - + ]: 4945 : if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
# 1056 : 4945 : auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error);
# 1057 [ + + ]: 4945 : if (!provider) return nullptr;
# 1058 : 4941 : return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
# 1059 : 4945 : }
# 1060 : :
# 1061 : : /** Parse a script in a particular context. */
# 1062 : : std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
# 1063 : 6445 : {
# 1064 : 6445 : using namespace spanparsing;
# 1065 : :
# 1066 : 6445 : auto expr = Expr(sp);
# 1067 [ + + ]: 6445 : if (Func("pk", expr)) {
# 1068 : 609 : auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
# 1069 [ + + ]: 609 : if (!pubkey) {
# 1070 : 4 : error = strprintf("pk(): %s", error);
# 1071 : 4 : return nullptr;
# 1072 : 4 : }
# 1073 : 605 : ++key_exp_index;
# 1074 : 605 : return std::make_unique<PKDescriptor>(std::move(pubkey), ctx == ParseScriptContext::P2TR);
# 1075 : 609 : }
# 1076 [ + + ][ + + ]: 5836 : if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && Func("pkh", expr)) {
# [ + + ][ + + ]
# [ + + ]
# 1077 : 792 : auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
# 1078 [ + + ]: 792 : if (!pubkey) {
# 1079 : 16 : error = strprintf("pkh(): %s", error);
# 1080 : 16 : return nullptr;
# 1081 : 16 : }
# 1082 : 776 : ++key_exp_index;
# 1083 : 776 : return std::make_unique<PKHDescriptor>(std::move(pubkey));
# 1084 [ - + ]: 5044 : } else if (Func("pkh", expr)) {
# 1085 : 0 : error = "Can only have pkh at top level, in sh(), or in wsh()";
# 1086 : 0 : return nullptr;
# 1087 : 0 : }
# 1088 [ + + ][ + + ]: 5044 : if (ctx == ParseScriptContext::TOP && Func("combo", expr)) {
# [ + + ]
# 1089 : 245 : auto pubkey = ParsePubkey(key_exp_index, expr, ctx, out, error);
# 1090 [ + + ]: 245 : if (!pubkey) {
# 1091 : 4 : error = strprintf("combo(): %s", error);
# 1092 : 4 : return nullptr;
# 1093 : 4 : }
# 1094 : 241 : ++key_exp_index;
# 1095 : 241 : return std::make_unique<ComboDescriptor>(std::move(pubkey));
# 1096 [ + + ]: 4799 : } else if (Func("combo", expr)) {
# 1097 : 4 : error = "Can only have combo() at top level";
# 1098 : 4 : return nullptr;
# 1099 : 4 : }
# 1100 : 4795 : const bool multi = Func("multi", expr);
# 1101 [ + + ][ + + ]: 4795 : const bool sortedmulti = !multi && Func("sortedmulti", expr);
# 1102 [ + + ][ + + ]: 4795 : const bool multi_a = !(multi || sortedmulti) && Func("multi_a", expr);
# [ + + ]
# 1103 [ + + ][ + + ]: 4795 : const bool sortedmulti_a = !(multi || sortedmulti || multi_a) && Func("sortedmulti_a", expr);
# [ + + ][ + + ]
# 1104 [ + + ][ + + ]: 4795 : if (((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && (multi || sortedmulti)) ||
# [ + + ][ + + ]
# [ + + ]
# 1105 [ + + ][ + + ]: 4795 : (ctx == ParseScriptContext::P2TR && (multi_a || sortedmulti_a))) {
# [ + - ]
# 1106 : 511 : auto threshold = Expr(expr);
# 1107 : 511 : uint32_t thres;
# 1108 : 511 : std::vector<std::unique_ptr<PubkeyProvider>> providers;
# 1109 [ + + ]: 511 : if (!ParseUInt32(std::string(threshold.begin(), threshold.end()), &thres)) {
# 1110 : 4 : error = strprintf("Multi threshold '%s' is not valid", std::string(threshold.begin(), threshold.end()));
# 1111 : 4 : return nullptr;
# 1112 : 4 : }
# 1113 : 507 : size_t script_size = 0;
# 1114 [ + + ]: 21877 : while (expr.size()) {
# 1115 [ - + ]: 21390 : if (!Const(",", expr)) {
# 1116 : 0 : error = strprintf("Multi: expected ',', got '%c'", expr[0]);
# 1117 : 0 : return nullptr;
# 1118 : 0 : }
# 1119 : 21390 : auto arg = Expr(expr);
# 1120 : 21390 : auto pk = ParsePubkey(key_exp_index, arg, ctx, out, error);
# 1121 [ + + ]: 21390 : if (!pk) {
# 1122 : 20 : error = strprintf("Multi: %s", error);
# 1123 : 20 : return nullptr;
# 1124 : 20 : }
# 1125 : 21370 : script_size += pk->GetSize() + 1;
# 1126 : 21370 : providers.emplace_back(std::move(pk));
# 1127 : 21370 : key_exp_index++;
# 1128 : 21370 : }
# 1129 [ + + ][ + + ]: 487 : if ((multi || sortedmulti) && (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTISIG)) {
# [ - + ][ - + ]
# 1130 : 0 : error = strprintf("Cannot have %u keys in multisig; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTISIG);
# 1131 : 0 : return nullptr;
# 1132 [ + + ][ + + ]: 487 : } else if ((multi_a || sortedmulti_a) && (providers.empty() || providers.size() > MAX_PUBKEYS_PER_MULTI_A)) {
# [ - + ][ - + ]
# 1133 : 0 : error = strprintf("Cannot have %u keys in multi_a; must have between 1 and %d keys, inclusive", providers.size(), MAX_PUBKEYS_PER_MULTI_A);
# 1134 : 0 : return nullptr;
# 1135 [ + + ]: 487 : } else if (thres < 1) {
# 1136 : 4 : error = strprintf("Multisig threshold cannot be %d, must be at least 1", thres);
# 1137 : 4 : return nullptr;
# 1138 [ + + ]: 483 : } else if (thres > providers.size()) {
# 1139 : 4 : error = strprintf("Multisig threshold cannot be larger than the number of keys; threshold is %d but only %u keys specified", thres, providers.size());
# 1140 : 4 : return nullptr;
# 1141 : 4 : }
# 1142 [ + + ]: 479 : if (ctx == ParseScriptContext::TOP) {
# 1143 [ + + ]: 31 : if (providers.size() > 3) {
# 1144 : 4 : error = strprintf("Cannot have %u pubkeys in bare multisig; only at most 3 pubkeys", providers.size());
# 1145 : 4 : return nullptr;
# 1146 : 4 : }
# 1147 : 31 : }
# 1148 [ + + ]: 475 : if (ctx == ParseScriptContext::P2SH) {
# 1149 : : // This limits the maximum number of compressed pubkeys to 15.
# 1150 [ + + ]: 104 : if (script_size + 3 > MAX_SCRIPT_ELEMENT_SIZE) {
# 1151 : 8 : error = strprintf("P2SH script is too large, %d bytes is larger than %d bytes", script_size + 3, MAX_SCRIPT_ELEMENT_SIZE);
# 1152 : 8 : return nullptr;
# 1153 : 8 : }
# 1154 : 104 : }
# 1155 [ + + ][ + + ]: 467 : if (multi || sortedmulti) {
# 1156 : 327 : return std::make_unique<MultisigDescriptor>(thres, std::move(providers), sortedmulti);
# 1157 : 327 : } else {
# 1158 : 140 : return std::make_unique<MultiADescriptor>(thres, std::move(providers), sortedmulti_a);
# 1159 : 140 : }
# 1160 [ - + ][ - + ]: 4284 : } else if (multi || sortedmulti) {
# 1161 : 0 : error = "Can only have multi/sortedmulti at top level, in sh(), or in wsh()";
# 1162 : 0 : return nullptr;
# 1163 [ - + ][ - + ]: 4284 : } else if (multi_a || sortedmulti_a) {
# 1164 : 0 : error = "Can only have multi_a/sortedmulti_a inside tr()";
# 1165 : 0 : return nullptr;
# 1166 : 0 : }
# 1167 [ + + ][ + + ]: 4284 : if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wpkh", expr)) {
# [ + + ][ + + ]
# 1168 : 1581 : auto pubkey = ParsePubkey(key_exp_index, expr, ParseScriptContext::P2WPKH, out, error);
# 1169 [ + + ]: 1581 : if (!pubkey) {
# 1170 : 12 : error = strprintf("wpkh(): %s", error);
# 1171 : 12 : return nullptr;
# 1172 : 12 : }
# 1173 : 1569 : key_exp_index++;
# 1174 : 1569 : return std::make_unique<WPKHDescriptor>(std::move(pubkey));
# 1175 [ + + ]: 2703 : } else if (Func("wpkh", expr)) {
# 1176 : 4 : error = "Can only have wpkh() at top level or inside sh()";
# 1177 : 4 : return nullptr;
# 1178 : 4 : }
# 1179 [ + + ][ + + ]: 2699 : if (ctx == ParseScriptContext::TOP && Func("sh", expr)) {
# [ + + ]
# 1180 : 1042 : auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error);
# 1181 [ + + ][ - + ]: 1042 : if (!desc || expr.size()) return nullptr;
# 1182 : 1014 : return std::make_unique<SHDescriptor>(std::move(desc));
# 1183 [ + + ]: 1657 : } else if (Func("sh", expr)) {
# 1184 : 8 : error = "Can only have sh() at top level";
# 1185 : 8 : return nullptr;
# 1186 : 8 : }
# 1187 [ + + ][ + + ]: 1649 : if ((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH) && Func("wsh", expr)) {
# [ + + ][ + + ]
# 1188 : 262 : auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2WSH, out, error);
# 1189 [ + + ][ - + ]: 262 : if (!desc || expr.size()) return nullptr;
# 1190 : 222 : return std::make_unique<WSHDescriptor>(std::move(desc));
# 1191 [ + + ]: 1387 : } else if (Func("wsh", expr)) {
# 1192 : 4 : error = "Can only have wsh() at top level or inside sh()";
# 1193 : 4 : return nullptr;
# 1194 : 4 : }
# 1195 [ + + ][ + + ]: 1383 : if (ctx == ParseScriptContext::TOP && Func("addr", expr)) {
# [ + + ]
# 1196 : 22 : CTxDestination dest = DecodeDestination(std::string(expr.begin(), expr.end()));
# 1197 [ + + ]: 22 : if (!IsValidDestination(dest)) {
# 1198 : 4 : error = "Address is not valid";
# 1199 : 4 : return nullptr;
# 1200 : 4 : }
# 1201 : 18 : return std::make_unique<AddressDescriptor>(std::move(dest));
# 1202 [ - + ]: 1361 : } else if (Func("addr", expr)) {
# 1203 : 0 : error = "Can only have addr() at top level";
# 1204 : 0 : return nullptr;
# 1205 : 0 : }
# 1206 [ + + ][ + + ]: 1361 : if (ctx == ParseScriptContext::TOP && Func("tr", expr)) {
# [ + + ]
# 1207 : 889 : auto arg = Expr(expr);
# 1208 : 889 : auto internal_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);
# 1209 [ - + ]: 889 : if (!internal_key) {
# 1210 : 0 : error = strprintf("tr(): %s", error);
# 1211 : 0 : return nullptr;
# 1212 : 0 : }
# 1213 : 889 : ++key_exp_index;
# 1214 : 889 : std::vector<std::unique_ptr<DescriptorImpl>> subscripts; //!< list of script subexpressions
# 1215 : 889 : std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts)
# 1216 [ + + ]: 889 : if (expr.size()) {
# 1217 [ - + ]: 280 : if (!Const(",", expr)) {
# 1218 : 0 : error = strprintf("tr: expected ',', got '%c'", expr[0]);
# 1219 : 0 : return nullptr;
# 1220 : 0 : }
# 1221 : : /** The path from the top of the tree to what we're currently processing.
# 1222 : : * branches[i] == false: left branch in the i'th step from the top; true: right branch.
# 1223 : : */
# 1224 : 280 : std::vector<bool> branches;
# 1225 : : // Loop over all provided scripts. In every iteration exactly one script will be processed.
# 1226 : : // Use a do-loop because inside this if-branch we expect at least one script.
# 1227 : 716 : do {
# 1228 : : // First process all open braces.
# 1229 [ + + ]: 1152 : while (Const("{", expr)) {
# 1230 : 436 : branches.push_back(false); // new left branch
# 1231 [ - + ]: 436 : if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) {
# 1232 : 0 : error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT);
# 1233 : 0 : return nullptr;
# 1234 : 0 : }
# 1235 : 436 : }
# 1236 : : // Process the actual script expression.
# 1237 : 716 : auto sarg = Expr(expr);
# 1238 : 716 : subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2TR, out, error));
# 1239 [ - + ]: 716 : if (!subscripts.back()) return nullptr;
# 1240 : 716 : depths.push_back(branches.size());
# 1241 : : // Process closing braces; one is expected for every right branch we were in.
# 1242 [ + + ][ + + ]: 1152 : while (branches.size() && branches.back()) {
# [ + + ]
# 1243 [ - + ]: 436 : if (!Const("}", expr)) {
# 1244 : 0 : error = strprintf("tr(): expected '}' after script expression");
# 1245 : 0 : return nullptr;
# 1246 : 0 : }
# 1247 : 436 : branches.pop_back(); // move up one level after encountering '}'
# 1248 : 436 : }
# 1249 : : // If after that, we're at the end of a left branch, expect a comma.
# 1250 [ + + ][ + + ]: 716 : if (branches.size() && !branches.back()) {
# [ + - ]
# 1251 [ - + ]: 436 : if (!Const(",", expr)) {
# 1252 : 0 : error = strprintf("tr(): expected ',' after script expression");
# 1253 : 0 : return nullptr;
# 1254 : 0 : }
# 1255 : 436 : branches.back() = true; // And now we're in a right branch.
# 1256 : 436 : }
# 1257 [ + + ]: 716 : } while (branches.size());
# 1258 : : // After we've explored a whole tree, we must be at the end of the expression.
# 1259 [ - + ]: 280 : if (expr.size()) {
# 1260 : 0 : error = strprintf("tr(): expected ')' after script expression");
# 1261 : 0 : return nullptr;
# 1262 : 0 : }
# 1263 : 280 : }
# 1264 : 889 : assert(TaprootBuilder::ValidDepths(depths));
# 1265 : 0 : return std::make_unique<TRDescriptor>(std::move(internal_key), std::move(subscripts), std::move(depths));
# 1266 [ - + ]: 889 : } else if (Func("tr", expr)) {
# 1267 : 0 : error = "Can only have tr at top level";
# 1268 : 0 : return nullptr;
# 1269 : 0 : }
# 1270 [ + + ][ + + ]: 472 : if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
# [ + + ]
# 1271 : 447 : std::string str(expr.begin(), expr.end());
# 1272 [ + + ]: 447 : if (!IsHex(str)) {
# 1273 : 2 : error = "Raw script is not hex";
# 1274 : 2 : return nullptr;
# 1275 : 2 : }
# 1276 : 445 : auto bytes = ParseHex(str);
# 1277 : 445 : return std::make_unique<RawDescriptor>(CScript(bytes.begin(), bytes.end()));
# 1278 [ - + ]: 447 : } else if (Func("raw", expr)) {
# 1279 : 0 : error = "Can only have raw() at top level";
# 1280 : 0 : return nullptr;
# 1281 : 0 : }
# 1282 [ + + ]: 25 : if (ctx == ParseScriptContext::P2SH) {
# 1283 : 4 : error = "A function is needed within P2SH";
# 1284 : 4 : return nullptr;
# 1285 [ + + ]: 21 : } else if (ctx == ParseScriptContext::P2WSH) {
# 1286 : 4 : error = "A function is needed within P2WSH";
# 1287 : 4 : return nullptr;
# 1288 : 4 : }
# 1289 : 17 : error = strprintf("'%s' is not a valid descriptor function", std::string(expr.begin(), expr.end()));
# 1290 : 17 : return nullptr;
# 1291 : 25 : }
# 1292 : :
# 1293 : : std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
# 1294 : 174706 : {
# 1295 : 174706 : std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, false);
# 1296 : 174706 : KeyOriginInfo info;
# 1297 [ + + ]: 174706 : if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
# 1298 : 174202 : return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
# 1299 : 174202 : }
# 1300 : 504 : return key_provider;
# 1301 : 174706 : }
# 1302 : :
# 1303 : : std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseScriptContext ctx, const SigningProvider& provider)
# 1304 : 4353 : {
# 1305 : 4353 : unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02};
# 1306 : 4353 : std::copy(xkey.begin(), xkey.end(), full_key + 1);
# 1307 : 4353 : CPubKey pubkey(full_key);
# 1308 : 4353 : std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, true);
# 1309 : 4353 : KeyOriginInfo info;
# 1310 [ + - ]: 4353 : if (provider.GetKeyOriginByXOnly(xkey, info)) {
# 1311 : 4353 : return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
# 1312 : 4353 : }
# 1313 : 0 : return key_provider;
# 1314 : 4353 : }
# 1315 : :
# 1316 : : std::unique_ptr<DescriptorImpl> InferMultiA(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
# 1317 : 28 : {
# 1318 : 28 : auto match = MatchMultiA(script);
# 1319 [ - + ]: 28 : if (!match) return {};
# 1320 : 28 : std::vector<std::unique_ptr<PubkeyProvider>> keys;
# 1321 : 28 : keys.reserve(match->second.size());
# 1322 [ + + ]: 4052 : for (const auto keyspan : match->second) {
# 1323 [ - + ]: 4052 : if (keyspan.size() != 32) return {};
# 1324 : 4052 : auto key = InferXOnlyPubkey(XOnlyPubKey{keyspan}, ctx, provider);
# 1325 [ - + ]: 4052 : if (!key) return {};
# 1326 : 4052 : keys.push_back(std::move(key));
# 1327 : 4052 : }
# 1328 : 28 : return std::make_unique<MultiADescriptor>(match->first, std::move(keys));
# 1329 : 28 : }
# 1330 : :
# 1331 : : std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
# 1332 : 227545 : {
# 1333 [ + + ][ + + ]: 227545 : if (ctx == ParseScriptContext::P2TR && script.size() == 34 && script[0] == 32 && script[33] == OP_CHECKSIG) {
# [ + - ][ + - ]
# 1334 : 184 : XOnlyPubKey key{Span{script}.subspan(1, 32)};
# 1335 : 184 : return std::make_unique<PKDescriptor>(InferXOnlyPubkey(key, ctx, provider), true);
# 1336 : 184 : }
# 1337 : :
# 1338 [ + + ]: 227361 : if (ctx == ParseScriptContext::P2TR) {
# 1339 : 28 : auto ret = InferMultiA(script, ctx, provider);
# 1340 [ + - ]: 28 : if (ret) return ret;
# 1341 : 28 : }
# 1342 : :
# 1343 : 227333 : std::vector<std::vector<unsigned char>> data;
# 1344 : 227333 : TxoutType txntype = Solver(script, data);
# 1345 : :
# 1346 [ + + ][ + + ]: 227333 : if (txntype == TxoutType::PUBKEY && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
# [ + + ][ + - ]
# 1347 : 22368 : CPubKey pubkey(data[0]);
# 1348 [ + - ]: 22368 : if (pubkey.IsValid()) {
# 1349 : 22368 : return std::make_unique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
# 1350 : 22368 : }
# 1351 : 22368 : }
# 1352 [ + + ][ + + ]: 204965 : if (txntype == TxoutType::PUBKEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
# [ + + ][ + - ]
# 1353 : 54393 : uint160 hash(data[0]);
# 1354 : 54393 : CKeyID keyid(hash);
# 1355 : 54393 : CPubKey pubkey;
# 1356 [ + + ]: 54393 : if (provider.GetPubKey(keyid, pubkey)) {
# 1357 : 53767 : return std::make_unique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
# 1358 : 53767 : }
# 1359 : 54393 : }
# 1360 [ + + ][ + + ]: 151198 : if (txntype == TxoutType::WITNESS_V0_KEYHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) {
# [ + - ]
# 1361 : 99179 : uint160 hash(data[0]);
# 1362 : 99179 : CKeyID keyid(hash);
# 1363 : 99179 : CPubKey pubkey;
# 1364 [ + + ]: 99179 : if (provider.GetPubKey(keyid, pubkey)) {
# 1365 : 92424 : return std::make_unique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
# 1366 : 92424 : }
# 1367 : 99179 : }
# 1368 [ + + ][ + + ]: 58774 : if (txntype == TxoutType::MULTISIG && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH)) {
# [ + + ][ + - ]
# 1369 : 2931 : std::vector<std::unique_ptr<PubkeyProvider>> providers;
# 1370 [ + + ]: 9078 : for (size_t i = 1; i + 1 < data.size(); ++i) {
# 1371 : 6147 : CPubKey pubkey(data[i]);
# 1372 : 6147 : providers.push_back(InferPubkey(pubkey, ctx, provider));
# 1373 : 6147 : }
# 1374 : 2931 : return std::make_unique<MultisigDescriptor>((int)data[0][0], std::move(providers));
# 1375 : 2931 : }
# 1376 [ + + ][ + - ]: 55843 : if (txntype == TxoutType::SCRIPTHASH && ctx == ParseScriptContext::TOP) {
# 1377 : 26235 : uint160 hash(data[0]);
# 1378 : 26235 : CScriptID scriptid(hash);
# 1379 : 26235 : CScript subscript;
# 1380 [ + + ]: 26235 : if (provider.GetCScript(scriptid, subscript)) {
# 1381 : 25635 : auto sub = InferScript(subscript, ParseScriptContext::P2SH, provider);
# 1382 [ + - ]: 25635 : if (sub) return std::make_unique<SHDescriptor>(std::move(sub));
# 1383 : 25635 : }
# 1384 : 26235 : }
# 1385 [ + + ][ + + ]: 30208 : if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && (ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH)) {
# [ + - ]
# 1386 : 2976 : CScriptID scriptid;
# 1387 : 2976 : CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
# 1388 : 2976 : CScript subscript;
# 1389 [ + + ]: 2976 : if (provider.GetCScript(scriptid, subscript)) {
# 1390 : 2758 : auto sub = InferScript(subscript, ParseScriptContext::P2WSH, provider);
# 1391 [ + - ]: 2758 : if (sub) return std::make_unique<WSHDescriptor>(std::move(sub));
# 1392 : 2758 : }
# 1393 : 2976 : }
# 1394 [ + + ][ + - ]: 27450 : if (txntype == TxoutType::WITNESS_V1_TAPROOT && ctx == ParseScriptContext::TOP) {
# 1395 : : // Extract x-only pubkey from output.
# 1396 : 4222 : XOnlyPubKey pubkey;
# 1397 : 4222 : std::copy(data[0].begin(), data[0].end(), pubkey.begin());
# 1398 : : // Request spending data.
# 1399 : 4222 : TaprootSpendData tap;
# 1400 [ + + ]: 4222 : if (provider.GetTaprootSpendData(pubkey, tap)) {
# 1401 : : // If found, convert it back to tree form.
# 1402 : 117 : auto tree = InferTaprootTree(tap, pubkey);
# 1403 [ + - ]: 117 : if (tree) {
# 1404 : : // If that works, try to infer subdescriptors for all leaves.
# 1405 : 117 : bool ok = true;
# 1406 : 117 : std::vector<std::unique_ptr<DescriptorImpl>> subscripts; //!< list of script subexpressions
# 1407 : 117 : std::vector<int> depths; //!< depth in the tree of each subexpression (same length subscripts)
# 1408 [ + + ]: 212 : for (const auto& [depth, script, leaf_ver] : *tree) {
# 1409 : 212 : std::unique_ptr<DescriptorImpl> subdesc;
# 1410 [ + - ]: 212 : if (leaf_ver == TAPROOT_LEAF_TAPSCRIPT) {
# 1411 : 212 : subdesc = InferScript(script, ParseScriptContext::P2TR, provider);
# 1412 : 212 : }
# 1413 [ - + ]: 212 : if (!subdesc) {
# 1414 : 0 : ok = false;
# 1415 : 0 : break;
# 1416 : 212 : } else {
# 1417 : 212 : subscripts.push_back(std::move(subdesc));
# 1418 : 212 : depths.push_back(depth);
# 1419 : 212 : }
# 1420 : 212 : }
# 1421 [ + - ]: 117 : if (ok) {
# 1422 : 117 : auto key = InferXOnlyPubkey(tap.internal_key, ParseScriptContext::P2TR, provider);
# 1423 : 117 : return std::make_unique<TRDescriptor>(std::move(key), std::move(subscripts), std::move(depths));
# 1424 : 117 : }
# 1425 : 117 : }
# 1426 : 117 : }
# 1427 : 4222 : }
# 1428 : :
# 1429 : 27333 : CTxDestination dest;
# 1430 [ + + ]: 27333 : if (ExtractDestination(script, dest)) {
# 1431 [ + - ]: 12306 : if (GetScriptForDestination(dest) == script) {
# 1432 : 12306 : return std::make_unique<AddressDescriptor>(std::move(dest));
# 1433 : 12306 : }
# 1434 : 12306 : }
# 1435 : :
# 1436 : 15027 : return std::make_unique<RawDescriptor>(script);
# 1437 : 27333 : }
# 1438 : :
# 1439 : :
# 1440 : : } // namespace
# 1441 : :
# 1442 : : /** Check a descriptor checksum, and update desc to be the checksum-less part. */
# 1443 : : bool CheckChecksum(Span<const char>& sp, bool require_checksum, std::string& error, std::string* out_checksum = nullptr)
# 1444 : 5043 : {
# 1445 : 5043 : using namespace spanparsing;
# 1446 : :
# 1447 : 5043 : auto check_split = Split(sp, '#');
# 1448 [ + + ]: 5043 : if (check_split.size() > 2) {
# 1449 : 4 : error = "Multiple '#' symbols";
# 1450 : 4 : return false;
# 1451 : 4 : }
# 1452 [ + + ][ + + ]: 5039 : if (check_split.size() == 1 && require_checksum){
# 1453 : 9 : error = "Missing checksum";
# 1454 : 9 : return false;
# 1455 : 9 : }
# 1456 [ + + ]: 5030 : if (check_split.size() == 2) {
# 1457 [ + + ]: 2746 : if (check_split[1].size() != 8) {
# 1458 : 12 : error = strprintf("Expected 8 character checksum, not %u characters", check_split[1].size());
# 1459 : 12 : return false;
# 1460 : 12 : }
# 1461 : 2746 : }
# 1462 : 5018 : auto checksum = DescriptorChecksum(check_split[0]);
# 1463 [ + + ]: 5018 : if (checksum.empty()) {
# 1464 : 2 : error = "Invalid characters in payload";
# 1465 : 2 : return false;
# 1466 : 2 : }
# 1467 [ + + ]: 5016 : if (check_split.size() == 2) {
# 1468 [ + + ]: 2732 : if (!std::equal(checksum.begin(), checksum.end(), check_split[1].begin())) {
# 1469 : 17 : error = strprintf("Provided checksum '%s' does not match computed checksum '%s'", std::string(check_split[1].begin(), check_split[1].end()), checksum);
# 1470 : 17 : return false;
# 1471 : 17 : }
# 1472 : 2732 : }
# 1473 [ + + ]: 4999 : if (out_checksum) *out_checksum = std::move(checksum);
# 1474 : 4999 : sp = check_split[0];
# 1475 : 4999 : return true;
# 1476 : 5016 : }
# 1477 : :
# 1478 : : std::unique_ptr<Descriptor> Parse(const std::string& descriptor, FlatSigningProvider& out, std::string& error, bool require_checksum)
# 1479 : 4461 : {
# 1480 : 4461 : Span<const char> sp{descriptor};
# 1481 [ + + ]: 4461 : if (!CheckChecksum(sp, require_checksum, error)) return nullptr;
# 1482 : 4425 : uint32_t key_exp_index = 0;
# 1483 : 4425 : auto ret = ParseScript(key_exp_index, sp, ParseScriptContext::TOP, out, error);
# 1484 [ + - ][ + + ]: 4425 : if (sp.size() == 0 && ret) return std::unique_ptr<Descriptor>(std::move(ret));
# 1485 : 131 : return nullptr;
# 1486 : 4425 : }
# 1487 : :
# 1488 : : std::string GetDescriptorChecksum(const std::string& descriptor)
# 1489 : 582 : {
# 1490 : 582 : std::string ret;
# 1491 : 582 : std::string error;
# 1492 : 582 : Span<const char> sp{descriptor};
# 1493 [ + + ]: 582 : if (!CheckChecksum(sp, false, error, &ret)) return "";
# 1494 : 574 : return ret;
# 1495 : 582 : }
# 1496 : :
# 1497 : : std::unique_ptr<Descriptor> InferDescriptor(const CScript& script, const SigningProvider& provider)
# 1498 : 198940 : {
# 1499 : 198940 : return InferScript(script, ParseScriptContext::TOP, provider);
# 1500 : 198940 : }
# 1501 : :
# 1502 : : void DescriptorCache::CacheParentExtPubKey(uint32_t key_exp_pos, const CExtPubKey& xpub)
# 1503 : 7454 : {
# 1504 : 7454 : m_parent_xpubs[key_exp_pos] = xpub;
# 1505 : 7454 : }
# 1506 : :
# 1507 : : void DescriptorCache::CacheDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_index, const CExtPubKey& xpub)
# 1508 : 5724 : {
# 1509 : 5724 : auto& xpubs = m_derived_xpubs[key_exp_pos];
# 1510 : 5724 : xpubs[der_index] = xpub;
# 1511 : 5724 : }
# 1512 : :
# 1513 : : void DescriptorCache::CacheLastHardenedExtPubKey(uint32_t key_exp_pos, const CExtPubKey& xpub)
# 1514 : 5231 : {
# 1515 : 5231 : m_last_hardened_xpubs[key_exp_pos] = xpub;
# 1516 : 5231 : }
# 1517 : :
# 1518 : : bool DescriptorCache::GetCachedParentExtPubKey(uint32_t key_exp_pos, CExtPubKey& xpub) const
# 1519 : 552715 : {
# 1520 : 552715 : const auto& it = m_parent_xpubs.find(key_exp_pos);
# 1521 [ + + ]: 552715 : if (it == m_parent_xpubs.end()) return false;
# 1522 : 549194 : xpub = it->second;
# 1523 : 549194 : return true;
# 1524 : 552715 : }
# 1525 : :
# 1526 : : bool DescriptorCache::GetCachedDerivedExtPubKey(uint32_t key_exp_pos, uint32_t der_index, CExtPubKey& xpub) const
# 1527 : 555482 : {
# 1528 : 555482 : const auto& key_exp_it = m_derived_xpubs.find(key_exp_pos);
# 1529 [ + + ]: 555482 : if (key_exp_it == m_derived_xpubs.end()) return false;
# 1530 : 4678 : const auto& der_it = key_exp_it->second.find(der_index);
# 1531 [ + + ]: 4678 : if (der_it == key_exp_it->second.end()) return false;
# 1532 : 736 : xpub = der_it->second;
# 1533 : 736 : return true;
# 1534 : 4678 : }
# 1535 : :
# 1536 : : bool DescriptorCache::GetCachedLastHardenedExtPubKey(uint32_t key_exp_pos, CExtPubKey& xpub) const
# 1537 : 1692 : {
# 1538 : 1692 : const auto& it = m_last_hardened_xpubs.find(key_exp_pos);
# 1539 [ + + ]: 1692 : if (it == m_last_hardened_xpubs.end()) return false;
# 1540 : 327 : xpub = it->second;
# 1541 : 327 : return true;
# 1542 : 1692 : }
# 1543 : :
# 1544 : : DescriptorCache DescriptorCache::MergeAndDiff(const DescriptorCache& other)
# 1545 : 171284 : {
# 1546 : 171284 : DescriptorCache diff;
# 1547 [ + + ]: 171284 : for (const auto& parent_xpub_pair : other.GetCachedParentExtPubKeys()) {
# 1548 : 1943 : CExtPubKey xpub;
# 1549 [ + + ]: 1943 : if (GetCachedParentExtPubKey(parent_xpub_pair.first, xpub)) {
# 1550 [ - + ]: 6 : if (xpub != parent_xpub_pair.second) {
# 1551 : 0 : throw std::runtime_error(std::string(__func__) + ": New cached parent xpub does not match already cached parent xpub");
# 1552 : 0 : }
# 1553 : 6 : continue;
# 1554 : 6 : }
# 1555 : 1937 : CacheParentExtPubKey(parent_xpub_pair.first, parent_xpub_pair.second);
# 1556 : 1937 : diff.CacheParentExtPubKey(parent_xpub_pair.first, parent_xpub_pair.second);
# 1557 : 1937 : }
# 1558 [ + + ]: 171284 : for (const auto& derived_xpub_map_pair : other.GetCachedDerivedExtPubKeys()) {
# 1559 [ + + ]: 1876 : for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
# 1560 : 1876 : CExtPubKey xpub;
# 1561 [ - + ]: 1876 : if (GetCachedDerivedExtPubKey(derived_xpub_map_pair.first, derived_xpub_pair.first, xpub)) {
# 1562 [ # # ]: 0 : if (xpub != derived_xpub_pair.second) {
# 1563 : 0 : throw std::runtime_error(std::string(__func__) + ": New cached derived xpub does not match already cached derived xpub");
# 1564 : 0 : }
# 1565 : 0 : continue;
# 1566 : 0 : }
# 1567 : 1876 : CacheDerivedExtPubKey(derived_xpub_map_pair.first, derived_xpub_pair.first, derived_xpub_pair.second);
# 1568 : 1876 : diff.CacheDerivedExtPubKey(derived_xpub_map_pair.first, derived_xpub_pair.first, derived_xpub_pair.second);
# 1569 : 1876 : }
# 1570 : 1876 : }
# 1571 [ + + ]: 171284 : for (const auto& lh_xpub_pair : other.GetCachedLastHardenedExtPubKeys()) {
# 1572 : 1365 : CExtPubKey xpub;
# 1573 [ - + ]: 1365 : if (GetCachedLastHardenedExtPubKey(lh_xpub_pair.first, xpub)) {
# 1574 [ # # ]: 0 : if (xpub != lh_xpub_pair.second) {
# 1575 : 0 : throw std::runtime_error(std::string(__func__) + ": New cached last hardened xpub does not match already cached last hardened xpub");
# 1576 : 0 : }
# 1577 : 0 : continue;
# 1578 : 0 : }
# 1579 : 1365 : CacheLastHardenedExtPubKey(lh_xpub_pair.first, lh_xpub_pair.second);
# 1580 : 1365 : diff.CacheLastHardenedExtPubKey(lh_xpub_pair.first, lh_xpub_pair.second);
# 1581 : 1365 : }
# 1582 : 171284 : return diff;
# 1583 : 171284 : }
# 1584 : :
# 1585 : : const ExtPubKeyMap DescriptorCache::GetCachedParentExtPubKeys() const
# 1586 : 343344 : {
# 1587 : 343344 : return m_parent_xpubs;
# 1588 : 343344 : }
# 1589 : :
# 1590 : : const std::unordered_map<uint32_t, ExtPubKeyMap> DescriptorCache::GetCachedDerivedExtPubKeys() const
# 1591 : 343344 : {
# 1592 : 343344 : return m_derived_xpubs;
# 1593 : 343344 : }
# 1594 : :
# 1595 : : const ExtPubKeyMap DescriptorCache::GetCachedLastHardenedExtPubKeys() const
# 1596 : 343093 : {
# 1597 : 343093 : return m_last_hardened_xpubs;
# 1598 : 343093 : }
|