Inside Bitcoin
Opening the selected file…
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.
251LOCK(cs_KeyStore);252std::set<CScriptID> set_script;253for (const auto& mi : mapScripts) {254set_script.insert(mi.first);255}256return set_script;257}259bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const260{261LOCK(cs_KeyStore);262ScriptMap::const_iterator mi = mapScripts.find(hash);263if (mi != mapScripts.end())264{265redeemScriptOut = (*mi).second;266return true;267}268return false;269}271CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)272{273// Only supports destinations which map to single public keys:274// P2PKH, P2WPKH, P2SH-P2WPKH, P2TR275if (auto id = std::get_if<PKHash>(&dest)) {276return ToKeyID(*id);277}278if (auto witness_id = std::get_if<WitnessV0KeyHash>(&dest)) {279return ToKeyID(*witness_id);280}281if (auto script_hash = std::get_if<ScriptHash>(&dest)) {282CScript script;283CScriptID script_id = ToScriptID(*script_hash);284CTxDestination inner_dest;285if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {286if (auto inner_witness_id = std::get_if<WitnessV0KeyHash>(&inner_dest)) {287return ToKeyID(*inner_witness_id);288}289}290}291if (auto output_key = std::get_if<WitnessV1Taproot>(&dest)) {292TaprootSpendData spenddata;293CPubKey pub;294if (store.GetTaprootSpendData(*output_key, spenddata)295&& !spenddata.internal_key.IsNull()296&& spenddata.merkle_root.IsNull()297&& store.GetPubKeyByXOnly(spenddata.internal_key, pub)) {298return pub.GetID();299}300}301return CKeyID();302}304void MultiSigningProvider::AddProvider(std::unique_ptr<SigningProvider> provider)305{306m_providers.push_back(std::move(provider));307}309bool MultiSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const310{311for (const auto& provider: m_providers) {312if (provider->GetCScript(scriptid, script)) return true;313}314return false;315}317bool MultiSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const318{319for (const auto& provider: m_providers) {320if (provider->GetPubKey(keyid, pubkey)) return true;321}322return false;323}326bool MultiSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const327{328for (const auto& provider: m_providers) {329if (provider->GetKeyOrigin(keyid, info)) return true;330}331return false;332}334bool MultiSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const335{336for (const auto& provider: m_providers) {337if (provider->GetKey(keyid, key)) return true;338}339return false;340}342bool MultiSigningProvider::GetTaprootSpendData(const XOnlyPubKey& output_key, TaprootSpendData& spenddata) const343{344for (const auto& provider: m_providers) {345if (provider->GetTaprootSpendData(output_key, spenddata)) return true;346}347return false;348}350bool MultiSigningProvider::GetTaprootBuilder(const XOnlyPubKey& output_key, TaprootBuilder& builder) const351{352for (const auto& provider: m_providers) {353if (provider->GetTaprootBuilder(output_key, builder)) return true;354}355return false;356}358/*static*/ TaprootBuilder::NodeInfo TaprootBuilder::Combine(NodeInfo&& a, NodeInfo&& b)359{360NodeInfo ret;361/* Iterate over all tracked leaves in a, add b's hash to their Merkle branch, and move them to ret. */362for (auto& leaf : a.leaves) {363leaf.merkle_branch.push_back(b.hash);364ret.leaves.emplace_back(std::move(leaf));365}366/* Iterate over all tracked leaves in b, add a's hash to their Merkle branch, and move them to ret. */367for (auto& leaf : b.leaves) {368leaf.merkle_branch.push_back(a.hash);369ret.leaves.emplace_back(std::move(leaf));370}371ret.hash = ComputeTapbranchHash(a.hash, b.hash);372return ret;373}375void TaprootSpendData::Merge(TaprootSpendData other)376{377// TODO: figure out how to better deal with conflicting information378// being merged.379if (internal_key.IsNull() && !other.internal_key.IsNull()) {380internal_key = other.internal_key;381}382if (merkle_root.IsNull() && !other.merkle_root.IsNull()) {383merkle_root = other.merkle_root;384}385for (auto& [key, control_blocks] : other.scripts) {386scripts[key].merge(std::move(control_blocks));387}388}390void TaprootBuilder::Insert(TaprootBuilder::NodeInfo&& node, int depth)391{392assert(depth >= 0 && (size_t)depth <= TAPROOT_CONTROL_MAX_NODE_COUNT);393/* We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing394* so would mean the Add() invocations do not correspond to a DFS traversal of a395* binary tree. */396if ((size_t)depth + 1 < m_branch.size()) {397m_valid = false;398return;399}400/* As long as an entry in the branch exists at the specified depth, combine it and propagate up.401* The 'node' variable is overwritten here with the newly combined node. */402while (m_valid && m_branch.size() > (size_t)depth && m_branch[depth].has_value()) {403node = Combine(std::move(node), std::move(*m_branch[depth]));404m_branch.pop_back();405if (depth == 0) m_valid = false; /* Can't propagate further up than the root */406--depth;407}408if (m_valid) {409/* Make sure the branch is big enough to place the new node. */410if (m_branch.size() <= (size_t)depth) m_branch.resize((size_t)depth + 1);411assert(!m_branch[depth].has_value());412m_branch[depth] = std::move(node);413}414}416/*static*/ bool TaprootBuilder::ValidDepths(const std::vector<int>& depths)417{418std::vector<bool> branch;419for (int depth : depths) {420// This inner loop corresponds to effectively the same logic on branch421// as what Insert() performs on the m_branch variable. Instead of422// storing a NodeInfo object, just remember whether or not there is one423// at that depth.424if (depth < 0 || (size_t)depth > TAPROOT_CONTROL_MAX_NODE_COUNT) return false;425if ((size_t)depth + 1 < branch.size()) return false;426while (branch.size() > (size_t)depth && branch[depth]) {427branch.pop_back();428if (depth == 0) return false;429--depth;430}431if (branch.size() <= (size_t)depth) branch.resize((size_t)depth + 1);432assert(!branch[depth]);433branch[depth] = true;434}435// And this check corresponds to the IsComplete() check on m_branch.436return branch.size() == 0 || (branch.size() == 1 && branch[0]);437}439TaprootBuilder& TaprootBuilder::Add(int depth, std::span<const unsigned char> script, int leaf_version, bool track)440{441assert((leaf_version & ~TAPROOT_LEAF_MASK) == 0);442if (!IsValid()) return *this;443/* Construct NodeInfo object with leaf hash and (if track is true) also leaf information. */444NodeInfo node;445node.hash = ComputeTapleafHash(leaf_version, script);446if (track) node.leaves.emplace_back(LeafInfo{std::vector<unsigned char>(script.begin(), script.end()), leaf_version, {}});447/* Insert into the branch. */448Insert(std::move(node), depth);449return *this;450}452TaprootBuilder& TaprootBuilder::AddOmitted(int depth, const uint256& hash)453{454if (!IsValid()) return *this;455/* Construct NodeInfo object with the hash directly, and insert it into the branch. */456NodeInfo node;457node.hash = hash;458Insert(std::move(node), depth);459return *this;460}462TaprootBuilder& TaprootBuilder::Finalize(const XOnlyPubKey& internal_key)463{464/* Can only call this function when IsComplete() is true. */465assert(IsComplete());466m_internal_key = internal_key;467auto ret = m_internal_key.CreateTapTweak(m_branch.size() == 0 ? nullptr : &m_branch[0]->hash);468assert(ret.has_value());469std::tie(m_output_key, m_parity) = *ret;470return *this;471}473WitnessV1Taproot TaprootBuilder::GetOutput() { return WitnessV1Taproot{m_output_key}; }475TaprootSpendData TaprootBuilder::GetSpendData() const476{477assert(IsComplete());478assert(m_output_key.IsFullyValid());479TaprootSpendData spd;480spd.merkle_root = m_branch.size() == 0 ? uint256() : m_branch[0]->hash;481spd.internal_key = m_internal_key;482if (m_branch.size()) {483// If any script paths exist, they have been combined into the root m_branch[0]484// by now. Compute the control block for each of its tracked leaves, and put them in485// spd.scripts.486for (const auto& leaf : m_branch[0]->leaves) {487std::vector<unsigned char> control_block;488control_block.resize(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * leaf.merkle_branch.size());489control_block[0] = leaf.leaf_version | (m_parity ? 1 : 0);490std::copy(m_internal_key.begin(), m_internal_key.end(), control_block.begin() + 1);491if (leaf.merkle_branch.size()) {492std::copy(leaf.merkle_branch[0].begin(),493leaf.merkle_branch[0].begin() + TAPROOT_CONTROL_NODE_SIZE * leaf.merkle_branch.size(),494control_block.begin() + TAPROOT_CONTROL_BASE_SIZE);495}496spd.scripts[{leaf.script, leaf.leaf_version}].insert(std::move(control_block));497}498}499return spd;500}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.