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.
1501public:1502WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}1503std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }1504bool IsSingleType() const final { return true; }1506std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }1508std::optional<int64_t> MaxSatSize(bool use_max_sig) const override {1509if (const auto sat_size = m_subdescriptor_args[0]->MaxSatSize(use_max_sig)) {1510if (const auto subscript_size = m_subdescriptor_args[0]->ScriptSize()) {1511return GetSizeOfCompactSize(*subscript_size) + *subscript_size + *sat_size;1512}1513}1514return {};1515}1517std::optional<int64_t> MaxSatisfactionWeight(bool use_max_sig) const override {1518return MaxSatSize(use_max_sig);1519}1521std::optional<int64_t> MaxSatisfactionElems() const override {1522if (const auto sub_elems = m_subdescriptor_args[0]->MaxSatisfactionElems()) return 1 + *sub_elems;1523return {};1524}1526std::unique_ptr<DescriptorImpl> Clone() const override1527{1528return std::make_unique<WSHDescriptor>(m_subdescriptor_args.at(0)->Clone());1529}1530};1532/** A parsed tr(...) descriptor. */1533class TRDescriptor final : public DescriptorImpl1534{1535std::vector<int> m_depths;1536protected:1537std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript> scripts, FlatSigningProvider& out) const override1538{1539TaprootBuilder builder;1540assert(m_depths.size() == scripts.size());1541for (size_t pos = 0; pos < m_depths.size(); ++pos) {1542builder.Add(m_depths[pos], scripts[pos], TAPROOT_LEAF_TAPSCRIPT);1543}1544if (!builder.IsComplete()) return {};1545assert(keys.size() == 1);1546XOnlyPubKey xpk(keys[0]);1547if (!xpk.IsFullyValid()) return {};1548builder.Finalize(xpk);1549WitnessV1Taproot output = builder.GetOutput();1550out.tr_trees[output] = builder;1551return Vector(GetScriptForDestination(output));1552}1553bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override1554{1555if (m_depths.empty()) {1556// If there are no sub-descriptors and a PRIVATE string1557// is requested, return `false` to indicate that the presence1558// of a private key depends solely on the internal key (which is checked1559// in the caller), not on any sub-descriptor. This ensures correct behavior for1560// descriptors like tr(internal_key) when checking for private keys.1561return type != StringType::PRIVATE;1562}1563std::vector<bool> path;1564bool is_private{type == StringType::PRIVATE};1565// For private string output, track if at least one key has a private key available.1566// Initialize to true for non-private types.1567bool any_success{!is_private};1569for (size_t pos = 0; pos < m_depths.size(); ++pos) {1570if (pos) ret += ',';1571while ((int)path.size() <= m_depths[pos]) {1572if (path.size()) ret += '{';1573path.push_back(false);1574}1575std::string tmp;1576bool subscript_res{m_subdescriptor_args[pos]->ToStringHelper(arg, tmp, type, cache)};1577if (!is_private && !subscript_res) return false;1578any_success = any_success || subscript_res;1579ret += tmp;1580while (!path.empty() && path.back()) {1581if (path.size() > 1) ret += '}';1582path.pop_back();1583}1584if (!path.empty()) path.back() = true;1585}1586return any_success;1587}1588public:1589TRDescriptor(std::unique_ptr<PubkeyProvider> internal_key, std::vector<std::unique_ptr<DescriptorImpl>> descs, std::vector<int> depths) :1590DescriptorImpl(Vector(std::move(internal_key)), std::move(descs), "tr"), m_depths(std::move(depths))1591{1592assert(m_subdescriptor_args.size() == m_depths.size());1593}1594std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }1595bool IsSingleType() const final { return true; }1597std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }1599std::optional<int64_t> MaxSatisfactionWeight(bool) const override {1600// FIXME: We assume keypath spend, which can lead to very large underestimations.1601return 1 + 65;1602}1604std::optional<int64_t> MaxSatisfactionElems() const override {1605// FIXME: See above, we assume keypath spend.1606return 1;1607}1609std::unique_ptr<DescriptorImpl> Clone() const override1610{1611std::vector<std::unique_ptr<DescriptorImpl>> subdescs;1612subdescs.reserve(m_subdescriptor_args.size());1613std::transform(m_subdescriptor_args.begin(), m_subdescriptor_args.end(), std::back_inserter(subdescs), [](const std::unique_ptr<DescriptorImpl>& d) { return d->Clone(); });1614return std::make_unique<TRDescriptor>(m_pubkey_args.at(0)->Clone(), std::move(subdescs), m_depths);1615}1616};1618/* We instantiate Miniscript here with a simple integer as key type.1619* The value of these key integers are an index in the1620* DescriptorImpl::m_pubkey_args vector.1621*/1623/**1624* The context for converting a Miniscript descriptor into a Script.1625*/1626class ScriptMaker {1627//! Keys contained in the Miniscript (the evaluation of DescriptorImpl::m_pubkey_args).1628const std::vector<CPubKey>& m_keys;1629//! The script context we're operating within (Tapscript or P2WSH).1630const miniscript::MiniscriptContext m_script_ctx;1632//! Get the ripemd160(sha256()) hash of this key.1633//! Any key that is valid in a descriptor serializes as 32 bytes within a Tapscript context. So we1634//! must not hash the sign-bit byte in this case.1635uint160 GetHash160(uint32_t key) const {1636if (miniscript::IsTapscript(m_script_ctx)) {1637return Hash160(XOnlyPubKey{m_keys[key]});1638}1639return m_keys[key].GetID();1640}1642public:1643ScriptMaker(const std::vector<CPubKey>& keys LIFETIMEBOUND, const miniscript::MiniscriptContext script_ctx) : m_keys(keys), m_script_ctx{script_ctx} {}1645std::vector<unsigned char> ToPKBytes(uint32_t key) const {1646// In Tapscript keys always serialize as x-only, whether an x-only key was used in the descriptor or not.1647if (!miniscript::IsTapscript(m_script_ctx)) {1648return {m_keys[key].begin(), m_keys[key].end()};1649}1650const XOnlyPubKey xonly_pubkey{m_keys[key]};1651return {xonly_pubkey.begin(), xonly_pubkey.end()};1652}1654std::vector<unsigned char> ToPKHBytes(uint32_t key) const {1655auto id = GetHash160(key);1656return {id.begin(), id.end()};1657}1658};1660/**1661* The context for converting a Miniscript descriptor to its textual form.1662*/1663class StringMaker {1664//! To convert private keys for private descriptors.1665const SigningProvider* m_arg;1666//! Keys contained in the Miniscript (a reference to DescriptorImpl::m_pubkey_args).1667const std::vector<std::unique_ptr<PubkeyProvider>>& m_pubkeys;1668//! StringType to serialize keys1669const DescriptorImpl::StringType m_type;1670const DescriptorCache* m_cache;1672public:1673StringMaker(const SigningProvider* arg LIFETIMEBOUND,1674const std::vector<std::unique_ptr<PubkeyProvider>>& pubkeys LIFETIMEBOUND,1675DescriptorImpl::StringType type,1676const DescriptorCache* cache LIFETIMEBOUND)1677: m_arg(arg), m_pubkeys(pubkeys), m_type(type), m_cache(cache) {}1679std::optional<std::string> ToString(uint32_t key, bool& has_priv_key) const1680{1681std::string ret;1682has_priv_key = false;1683switch (m_type) {1684case DescriptorImpl::StringType::PUBLIC:1685ret = m_pubkeys[key]->ToString(PubkeyProvider::StringType::PUBLIC);1686break;1687case DescriptorImpl::StringType::PRIVATE:1688has_priv_key = m_pubkeys[key]->ToPrivateString(*m_arg, ret);1689break;1690case DescriptorImpl::StringType::NORMALIZED:1691if (!m_pubkeys[key]->ToNormalizedString(*m_arg, ret, m_cache)) return {};1692break;1693case DescriptorImpl::StringType::COMPAT:1694// For backwards compatibility, we do not pass StringType::COMPAT.1695// Prior to 31.0, COMPAT was not provided, so PUBLIC was in use. From this string,1696// DescriptorSPKM IDs were computed from this string, so the incorrect behavior1697// must be preserved for wallets with Miniscript descriptors to be loaded1698ret = m_pubkeys[key]->ToString(PubkeyProvider::StringType::PUBLIC);1699break;1700case DescriptorImpl::StringType::CANONICAL:1701ret = m_pubkeys[key]->ToString(PubkeyProvider::StringType::CANONICAL);1702break;1703}1704return ret;1705}1706};1708class MiniscriptDescriptor final : public DescriptorImpl1709{1710private:1711miniscript::Node<uint32_t> m_node;1713protected:1714std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, std::span<const CScript> scripts,1715FlatSigningProvider& provider) const override1716{1717const auto script_ctx{m_node.GetMsCtx()};1718for (const auto& key : keys) {1719if (miniscript::IsTapscript(script_ctx)) {1720provider.pubkeys.emplace(Hash160(XOnlyPubKey{key}), key);1721} else {1722provider.pubkeys.emplace(key.GetID(), key);1723}1724}1725return Vector(m_node.ToScript(ScriptMaker(keys, script_ctx)));1726}1728public:1729MiniscriptDescriptor(std::vector<std::unique_ptr<PubkeyProvider>> providers, miniscript::Node<uint32_t>&& node)1730: DescriptorImpl(std::move(providers), "?"), m_node(std::move(node))1731{1732// Traverse miniscript tree for unsafe use of older()1733miniscript::ForEachNode(m_node, [&](const miniscript::Node<uint32_t>& node) {1734if (node.Fragment() == miniscript::Fragment::OLDER) {1735const uint32_t raw = node.K();1736const uint32_t value_part = raw & ~CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG;1737if (value_part > CTxIn::SEQUENCE_LOCKTIME_MASK) {1738const bool is_time_based = (raw & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) != 0;1739if (is_time_based) {1740m_warnings.push_back(strprintf("time-based relative locktime: older(%u) > (65535 * 512) seconds is unsafe", raw));1741} else {1742m_warnings.push_back(strprintf("height-based relative locktime: older(%u) > 65535 blocks is unsafe", raw));1743}1744}1745}1746});1747}1749bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type,1750const DescriptorCache* cache = nullptr) const override