Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1751{1752bool has_priv_key{false};1753auto res = m_node.ToString(StringMaker(arg, m_pubkey_args, type, cache), has_priv_key);1754if (res) out = *res;1755if (type == StringType::PRIVATE) {1756Assume(res.has_value());1757return has_priv_key;1758} else {1759return res.has_value();1760}1761}1763bool IsSolvable() const override { return true; }1764bool IsSingleType() const final { return true; }1766std::optional<int64_t> ScriptSize() const override { return m_node.ScriptSize(); }1768std::optional<int64_t> MaxSatSize(bool) const override1769{1770// For Miniscript we always assume high-R ECDSA signatures.1771return m_node.GetWitnessSize();1772}1774std::optional<int64_t> MaxSatisfactionElems() const override1775{1776return m_node.GetStackSize();1777}1779std::unique_ptr<DescriptorImpl> Clone() const override1780{1781std::vector<std::unique_ptr<PubkeyProvider>> providers;1782providers.reserve(m_pubkey_args.size());1783for (const auto& arg : m_pubkey_args) {1784providers.push_back(arg->Clone());1785}1786return std::make_unique<MiniscriptDescriptor>(std::move(providers), m_node.Clone());1787}1788};1790/** A parsed rawtr(...) descriptor. */1791class RawTRDescriptor final : public DescriptorImpl1792{1793protected:1794std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript> scripts, FlatSigningProvider& out) const override1795{1796assert(keys.size() == 1);1797XOnlyPubKey xpk(keys[0]);1798if (!xpk.IsFullyValid()) return {};1799WitnessV1Taproot output{xpk};1800return Vector(GetScriptForDestination(output));1801}1802public:1803RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}1804std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }1805bool IsSingleType() const final { return true; }1807std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }1809std::optional<int64_t> MaxSatisfactionWeight(bool) const override {1810// We can't know whether there is a script path, so assume key path spend.1811return 1 + 65;1812}1814std::optional<int64_t> MaxSatisfactionElems() const override {1815// See above, we assume keypath spend.1816return 1;1817}1819std::unique_ptr<DescriptorImpl> Clone() const override1820{1821return std::make_unique<RawTRDescriptor>(m_pubkey_args.at(0)->Clone());1822}1823};1825/** A parsed unused(KEY) descriptor */1826class UnusedDescriptor final : public DescriptorImpl1827{1828protected:1829std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript> scripts, FlatSigningProvider& out) const override { return {}; }1830public:1831UnusedDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "unused") {}1832bool IsSingleType() const final { return true; }1833bool HasScripts() const override { return false; }1835std::unique_ptr<DescriptorImpl> Clone() const override1836{1837return std::make_unique<UnusedDescriptor>(m_pubkey_args.at(0)->Clone());1838}1839};1842////////////////////////////////////////////////////////////////////////////1843// Parser //1844////////////////////////////////////////////////////////////////////////////1846enum class ParseScriptContext {1847TOP, //!< Top-level context (script goes directly in scriptPubKey)1848P2SH, //!< Inside sh() (script becomes P2SH redeemScript)1849P2WPKH, //!< Inside wpkh() (no script, pubkey only)1850P2WSH, //!< Inside wsh() (script becomes v0 witness script)1851P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf)1852MUSIG, //!< Inside musig() (implies P2TR, cannot have nested musig())1853};1855/**1856* Parse a key path, being passed a split list of elements (the first element is ignored because it is always the key).1857*1858* @param[in] split BIP32 path string, using either ' or h for hardened derivation1859* @param[out] out Vector of parsed key paths1860* @param[out] apostrophe only updated if hardened derivation is found1861* @param[out] error parsing error message1862* @param[in] allow_multipath Allows the parsed path to use the multipath specifier1863* @param[out] has_hardened Records whether the path contains any hardened derivation1864* @returns false if parsing failed1865**/1866[[nodiscard]] bool ParseKeyPath(const std::vector<std::span<const char>>& split, std::vector<KeyPath>& out, bool& apostrophe, std::string& error, bool allow_multipath, bool& has_hardened)1867{1868auto parse_elem = [&](std::span<const char> elem) -> std::optional<uint32_t> {1869const auto parsed{ParseKeyPathElement(elem)};1870if (!parsed) {1871error = parsed.error();1872return std::nullopt;1873}1874if (parsed->is_hardened) {1875has_hardened = true;1876apostrophe = elem.back() == '\'';1877}1878return parsed->ChildNumber();1879};1881KeyPath path;1882struct MultipathSubstitutes {1883size_t placeholder_index;1884std::vector<uint32_t> values;1885};1886std::optional<MultipathSubstitutes> substitutes;1887has_hardened = false;1889for (size_t i = 1; i < split.size(); ++i) {1890const std::span<const char>& elem = split[i];1892// Check if element contains multipath specifier1893if (!elem.empty() && elem.front() == '<' && elem.back() == '>') {1894if (!allow_multipath) {1895error = strprintf("Key path value '%s' specifies multipath in a section where multipath is not allowed", std::string(elem.begin(), elem.end()));1896return false;1897}1898if (substitutes) {1899error = "Multiple multipath key path specifiers found";1900return false;1901}1903// Parse each possible value1904std::vector<std::span<const char>> nums = Split(std::span(elem.begin()+1, elem.end()-1), ";");1905if (nums.size() < 2) {1906error = "Multipath key path specifiers must have at least two items";1907return false;1908}1910substitutes.emplace();1911std::unordered_set<uint32_t> seen_substitutes;1912for (const auto& num : nums) {1913const auto& op_num = parse_elem(num);1914if (!op_num) return false;1915auto [_, inserted] = seen_substitutes.insert(*op_num);1916if (!inserted) {1917error = strprintf("Duplicated key path value %u in multipath specifier", *op_num);1918return false;1919}1920substitutes->values.emplace_back(*op_num);1921}1923path.emplace_back(); // Placeholder for multipath segment1924substitutes->placeholder_index = path.size() - 1;1925} else {1926const auto& op_num = parse_elem(elem);1927if (!op_num) return false;1928path.emplace_back(*op_num);1929}1930}1932if (!substitutes) {1933out.emplace_back(std::move(path));1934} else {1935// Replace the multipath placeholder with each value while generating paths1936for (uint32_t substitute : substitutes->values) {1937KeyPath branch_path = path;1938branch_path[substitutes->placeholder_index] = substitute;1939out.emplace_back(std::move(branch_path));1940}1941}1942return true;1943}1945[[nodiscard]] bool ParseKeyPath(const std::vector<std::span<const char>>& split, std::vector<KeyPath>& out, bool& apostrophe, std::string& error, bool allow_multipath)1946{1947bool dummy;1948return ParseKeyPath(split, out, apostrophe, error, allow_multipath, /*has_hardened=*/dummy);1949}1951static DeriveType ParseDeriveType(std::vector<std::span<const char>>& split, bool& apostrophe)1952{1953DeriveType type = DeriveType::NON_RANGED;1954if (std::ranges::equal(split.back(), std::span{"*"}.first(1))) {1955split.pop_back();1956type = DeriveType::UNHARDENED_RANGED;1957} else if (std::ranges::equal(split.back(), std::span{"*'"}.first(2)) || std::ranges::equal(split.back(), std::span{"*h"}.first(2))) {1958apostrophe = std::ranges::equal(split.back(), std::span{"*'"}.first(2));1959split.pop_back();1960type = DeriveType::HARDENED_RANGED;1961}1962return type;1963}1965/** Parse a public key that excludes origin information. */1966std::vector<std::unique_ptr<PubkeyProvider>> ParsePubkeyInner(uint32_t& key_exp_index, const std::span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error)1967{1968std::vector<std::unique_ptr<PubkeyProvider>> ret;1969bool permit_uncompressed = ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH;1970auto split = Split(sp, '/');1971std::string str(split[0].begin(), split[0].end());1972if (str.size() == 0) {1973error = "No key provided";1974return {};1975}1976if (IsSpace(str.front()) || IsSpace(str.back())) {1977error = strprintf("Key '%s' is invalid due to whitespace", str);1978return {};1979}1980if (split.size() == 1) {1981if (IsHex(str)) {1982std::vector<unsigned char> data = ParseHex(str);1983CPubKey pubkey(data);1984if (pubkey.IsValid() && !pubkey.IsValidNonHybrid()) {1985error = "Hybrid public keys are not allowed";1986return {};1987}1988if (pubkey.IsFullyValid()) {1989if (permit_uncompressed || pubkey.IsCompressed()) {1990ret.emplace_back(std::make_unique<ConstPubkeyProvider>(key_exp_index, pubkey, false));1991++key_exp_index;1992return ret;1993} else {1994error = "Uncompressed keys are not allowed";1995return {};1996}1997} else if (data.size() == 32 && ctx == ParseScriptContext::P2TR) {1998unsigned char fullkey[33] = {0x02};1999std::copy(data.begin(), data.end(), fullkey + 1);2000pubkey.Set(std::begin(fullkey), std::end(fullkey));