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.
751if (IsRangedDerivation()) {752out += "/*";753}754return out;755}756bool ToPrivateString(const SigningProvider& arg, std::string& out) const override757{758bool any_privkeys = false;759out = "musig(";760for (size_t i = 0; i < m_participants.size(); ++i) {761const auto& pubkey = m_participants.at(i);762if (i) out += ",";763std::string tmp;764if (pubkey->ToPrivateString(arg, tmp)) {765any_privkeys = true;766}767out += tmp;768}769out += ")";770out += FormatHDKeypath(m_path);771if (IsRangedDerivation()) {772out += "/*";773}774return any_privkeys;775}776bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) const override777{778out = "musig(";779for (size_t i = 0; i < m_participants.size(); ++i) {780const auto& pubkey = m_participants.at(i);781if (i) out += ",";782std::string tmp;783if (!pubkey->ToNormalizedString(arg, tmp, cache)) {784return false;785}786out += tmp;787}788out += ")";789out += FormatHDKeypath(m_path);790if (IsRangedDerivation()) {791out += "/*";792}793return true;794}796void GetPrivKey(int pos, const SigningProvider& arg, FlatSigningProvider& out) const override797{798// Get the private keys for any participants that we have799// If there is participant derivation, it will be done.800// If there is not, then the participant privkeys will be included directly801for (const auto& prov : m_participants) {802prov->GetPrivKey(pos, arg, out);803}804}806bool HavePrivateKeys(const SigningProvider& arg) const override807{808return std::ranges::all_of(m_participants, [&](const auto& prov) { return prov->HavePrivateKeys(arg); });809}811// Get RootPubKey and GetRootExtPubKey are used to return the single pubkey underlying the pubkey provider812// to be presented to the user in gethdkeys. As this is a multisig construction, there is no single underlying813// pubkey hence nothing should be returned.814// While the aggregate pubkey could be returned as the root (ext)pubkey, it is not a pubkey that anyone should815// be using by itself in a descriptor as it is unspendable without knowing its participants.816std::optional<CPubKey> GetRootPubKey() const override817{818return std::nullopt;819}820std::optional<CExtPubKey> GetRootExtPubKey() const override821{822return std::nullopt;823}825std::unique_ptr<PubkeyProvider> Clone() const override826{827std::vector<std::unique_ptr<PubkeyProvider>> providers;828providers.reserve(m_participants.size());829for (const std::unique_ptr<PubkeyProvider>& p : m_participants) {830providers.emplace_back(p->Clone());831}832return std::make_unique<MuSigPubkeyProvider>(m_expr_index, std::move(providers), m_path, m_derive);833}834bool IsBIP32() const override835{836// musig() can only be a BIP 32 key if all participants are bip32 too837return std::all_of(m_participants.begin(), m_participants.end(), [](const auto& pubkey) { return pubkey->IsBIP32(); });838}839size_t GetKeyCount() const override840{841return 1 + m_participants.size();842}843bool CanSelfExpand() const override844{845// Participants must be self expandable for all MuSig expressions to be self expandable; the aggregate pubkey cannot be stored846// in the descriptor cache, so even aggregate-then-derive still requires the self expansion of participants prior to aggregation.847for (const auto& key : m_participants) {848if (!key->CanSelfExpand()) return false;849}850return true;851}852};854/** Base class for all Descriptor implementations. */855class DescriptorImpl : public Descriptor856{857protected:858//! Public key arguments for this descriptor (size 1 for PK, PKH, WPKH; any size for WSH and Multisig).859const std::vector<std::unique_ptr<PubkeyProvider>> m_pubkey_args;860//! The string name of the descriptor function.861const std::string m_name;862//! Warnings (not including subdescriptors).863std::vector<std::string> m_warnings;865//! The sub-descriptor arguments (empty for everything but SH and WSH).866//! In doc/descriptors.md this is referred to as SCRIPT expressions sh(SCRIPT)867//! and wsh(SCRIPT), and distinct from KEY expressions and ADDR expressions.868//! Subdescriptors can only ever generate a single script.869const std::vector<std::unique_ptr<DescriptorImpl>> m_subdescriptor_args;871//! Return a serialization of anything except pubkey and script arguments, to be prepended to those.872virtual std::string ToStringExtra() const { return ""; }874/** A helper function to construct the scripts for this descriptor.875*876* This function is invoked once by ExpandHelper.877*878* @param pubkeys The evaluations of the m_pubkey_args field.879* @param scripts The evaluations of m_subdescriptor_args (one for each m_subdescriptor_args element).880* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.881* The origin info of the provided pubkeys is automatically added.882* @return A vector with scriptPubKeys for this descriptor.883*/884virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, std::span<const CScript> scripts, FlatSigningProvider& out) const = 0;886public:887DescriptorImpl(std::vector<std::unique_ptr<PubkeyProvider>> pubkeys, const std::string& name) : m_pubkey_args(std::move(pubkeys)), m_name(name), m_subdescriptor_args() {}888DescriptorImpl(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))) {}889DescriptorImpl(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)) {}891enum class StringType892{893PUBLIC,894PRIVATE,895NORMALIZED,896CANONICAL,897COMPAT, // string calculation that mustn't change over time to stay compatible with previous software versions898};900// NOLINTNEXTLINE(misc-no-recursion)901bool IsSolvable() const override902{903for (const auto& arg : m_subdescriptor_args) {904if (!arg->IsSolvable()) return false;905}906return true;907}909// NOLINTNEXTLINE(misc-no-recursion)910bool HavePrivateKeys(const SigningProvider& arg) const override911{912if (m_pubkey_args.empty() && m_subdescriptor_args.empty()) return false;914for (const auto& sub: m_subdescriptor_args) {915if (!sub->HavePrivateKeys(arg)) return false;916}918for (const auto& pubkey : m_pubkey_args) {919if (!pubkey->HavePrivateKeys(arg)) return false;920}922return true;923}925// NOLINTNEXTLINE(misc-no-recursion)926bool IsRange() const final927{928for (const auto& pubkey : m_pubkey_args) {929if (pubkey->IsRange()) return true;930}931for (const auto& arg : m_subdescriptor_args) {932if (arg->IsRange()) return true;933}934return false;935}937// NOLINTNEXTLINE(misc-no-recursion)938virtual bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const939{940size_t pos = 0;941bool is_private{type == StringType::PRIVATE};942// For private string output, track if at least one key has a private key available.943// Initialize to true for non-private types.944bool any_success{!is_private};945for (const auto& scriptarg : m_subdescriptor_args) {946if (pos++) ret += ",";947std::string tmp;948bool subscript_res{scriptarg->ToStringHelper(arg, tmp, type, cache)};949if (!is_private && !subscript_res) return false;950any_success = any_success || subscript_res;951ret += tmp;952}953return any_success;954}956// NOLINTNEXTLINE(misc-no-recursion)957virtual bool ToStringHelper(const SigningProvider* arg, std::string& out, const StringType type, const DescriptorCache* cache = nullptr) const958{959std::string extra = ToStringExtra();960size_t pos = extra.size() > 0 ? 1 : 0;961std::string ret = m_name + "(" + extra;962bool is_private{type == StringType::PRIVATE};963// For private string output, track if at least one key has a private key available.964// Initialize to true for non-private types.965bool any_success{!is_private};967for (const auto& pubkey : m_pubkey_args) {968if (pos++) ret += ",";969std::string tmp;970switch (type) {971case StringType::NORMALIZED:972if (!pubkey->ToNormalizedString(*arg, tmp, cache)) return false;973break;974case StringType::PRIVATE:975any_success = pubkey->ToPrivateString(*arg, tmp) || any_success;976break;977case StringType::PUBLIC:978tmp = pubkey->ToString(PubkeyProvider::StringType::PUBLIC);979break;980case StringType::COMPAT:981tmp = pubkey->ToString(PubkeyProvider::StringType::COMPAT);982break;983case StringType::CANONICAL:984tmp = pubkey->ToString(PubkeyProvider::StringType::CANONICAL);985break;986}987ret += tmp;988}989std::string subscript;990bool subscript_res{ToStringSubScriptHelper(arg, subscript, type, cache)};991if (!is_private && !subscript_res) return false;992any_success = any_success || subscript_res;993if (pos && subscript.size()) ret += ',';994out = std::move(ret) + std::move(subscript) + ")";995return any_success;996}998std::string ToString(bool compat_format) const final999{1000std::string ret;