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.
502std::optional<std::vector<std::tuple<int, std::vector<unsigned char>, int>>> InferTaprootTree(const TaprootSpendData& spenddata, const XOnlyPubKey& output)503{504// Verify that the output matches the assumed Merkle root and internal key.505auto tweak = spenddata.internal_key.CreateTapTweak(spenddata.merkle_root.IsNull() ? nullptr : &spenddata.merkle_root);506if (!tweak || tweak->first != output) return std::nullopt;507// If the Merkle root is 0, the tree is empty, and we're done.508std::vector<std::tuple<int, std::vector<unsigned char>, int>> ret;509if (spenddata.merkle_root.IsNull()) return ret;511/** Data structure to represent the nodes of the tree we're going to build. */512struct TreeNode {513/** Hash of this node, if known; 0 otherwise. */514uint256 hash;515/** The left and right subtrees (note that their order is irrelevant). */516std::unique_ptr<TreeNode> sub[2];517/** If this is known to be a leaf node, a pointer to the (script, leaf_ver) pair.518* nullptr otherwise. */519const std::pair<std::vector<unsigned char>, int>* leaf = nullptr;520/** Whether or not this node has been explored (is known to be a leaf, or known to have children). */521bool explored = false;522/** Whether or not this node is an inner node (unknown until explored = true). */523bool inner;524/** Whether or not we have produced output for this subtree. */525bool done = false;526};528// Build tree from the provided branches.529TreeNode root;530root.hash = spenddata.merkle_root;531for (const auto& [key, control_blocks] : spenddata.scripts) {532const auto& [script, leaf_ver] = key;533for (const auto& control : control_blocks) {534// Skip script records with nonsensical leaf version.535if (leaf_ver < 0 || leaf_ver >= 0x100 || leaf_ver & 1) continue;536// Skip script records with invalid control block sizes.537if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE ||538((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) continue;539// Skip script records that don't match the control block.540if ((control[0] & TAPROOT_LEAF_MASK) != leaf_ver) continue;541// Skip script records that don't match the provided Merkle root.542const uint256 leaf_hash = ComputeTapleafHash(leaf_ver, script);543const uint256 merkle_root = ComputeTaprootMerkleRoot(control, leaf_hash);544if (merkle_root != spenddata.merkle_root) continue;546TreeNode* node = &root;547size_t levels = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;548for (size_t depth = 0; depth < levels; ++depth) {549// Can't descend into a node which we already know is a leaf.550if (node->explored && !node->inner) return std::nullopt;552// Extract partner hash from Merkle branch in control block.553uint256 hash;554std::copy(control.begin() + TAPROOT_CONTROL_BASE_SIZE + (levels - 1 - depth) * TAPROOT_CONTROL_NODE_SIZE,555control.begin() + TAPROOT_CONTROL_BASE_SIZE + (levels - depth) * TAPROOT_CONTROL_NODE_SIZE,556hash.begin());558if (node->sub[0]) {559// Descend into the existing left or right branch.560bool desc = false;561for (int i = 0; i < 2; ++i) {562if (node->sub[i]->hash == hash || (node->sub[i]->hash.IsNull() && node->sub[1-i]->hash != hash)) {563node->sub[i]->hash = hash;564node = &*node->sub[1-i];565desc = true;566break;567}568}569if (!desc) return std::nullopt; // This probably requires a hash collision to hit.570} else {571// We're in an unexplored node. Create subtrees and descend.572node->explored = true;573node->inner = true;574node->sub[0] = std::make_unique<TreeNode>();575node->sub[1] = std::make_unique<TreeNode>();576node->sub[1]->hash = hash;577node = &*node->sub[0];578}579}580// Cannot turn a known inner node into a leaf.581if (node->sub[0]) return std::nullopt;582node->explored = true;583node->inner = false;584node->leaf = &key;585node->hash = leaf_hash;586}587}589// Recursive processing to turn the tree into flattened output. Use an explicit stack here to avoid590// overflowing the call stack (the tree may be 128 levels deep).591std::vector<TreeNode*> stack{&root};592while (!stack.empty()) {593TreeNode& node = *stack.back();594if (!node.explored) {595// Unexplored node, which means the tree is incomplete.596return std::nullopt;597} else if (!node.inner) {598// Leaf node; produce output.599ret.emplace_back(stack.size() - 1, node.leaf->first, node.leaf->second);600node.done = true;601stack.pop_back();602} else if (node.sub[0]->done && !node.sub[1]->done && !node.sub[1]->explored && !node.sub[1]->hash.IsNull() &&603ComputeTapbranchHash(node.sub[1]->hash, node.sub[1]->hash) == node.hash) {604// Whenever there are nodes with two identical subtrees under it, we run into a problem:605// the control blocks for the leaves underneath those will be identical as well, and thus606// they will all be matched to the same path in the tree. The result is that at the location607// where the duplicate occurred, the left child will contain a normal tree that can be explored608// and processed, but the right one will remain unexplored.609//610// This situation can be detected, by encountering an inner node with unexplored right subtree611// with known hash, and H_TapBranch(hash, hash) is equal to the parent node (this node)'s hash.612//613// To deal with this, simply process the left tree a second time (set its done flag to false;614// noting that the done flag of its children have already been set to false after processing615// those). To avoid ending up in an infinite loop, set the done flag of the right (unexplored)616// subtree to true.617node.sub[0]->done = false;618node.sub[1]->done = true;619} else if (node.sub[0]->done && node.sub[1]->done) {620// An internal node which we're finished with.621node.sub[0]->done = false;622node.sub[1]->done = false;623node.done = true;624stack.pop_back();625} else if (!node.sub[0]->done) {626// An internal node whose left branch hasn't been processed yet. Do so first.627stack.push_back(&*node.sub[0]);628} else if (!node.sub[1]->done) {629// An internal node whose right branch hasn't been processed yet. Do so first.630stack.push_back(&*node.sub[1]);631}632}634return ret;635}637std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> TaprootBuilder::GetTreeTuples() const638{639assert(IsComplete());640std::vector<std::tuple<uint8_t, uint8_t, std::vector<unsigned char>>> tuples;641if (m_branch.size()) {642const auto& leaves = m_branch[0]->leaves;643for (const auto& leaf : leaves) {644assert(leaf.merkle_branch.size() <= TAPROOT_CONTROL_MAX_NODE_COUNT);645uint8_t depth = (uint8_t)leaf.merkle_branch.size();646uint8_t leaf_ver = (uint8_t)leaf.leaf_version;647tuples.emplace_back(depth, leaf_ver, leaf.script);648}649}650return tuples;651}
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.