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.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <merkleblock.h>8#include <consensus/consensus.h>9#include <hash.h>10#include <util/overflow.h>13std::vector<unsigned char> BitsToBytes(const std::vector<bool>& bits)14{15std::vector<unsigned char> ret(CeilDiv(bits.size(), 8u));16for (unsigned int p = 0; p < bits.size(); p++) {17ret[p / 8] |= bits[p] << (p % 8);18}19return ret;20}22std::vector<bool> BytesToBits(const std::vector<unsigned char>& bytes)23{24std::vector<bool> ret(bytes.size() * 8);25for (unsigned int p = 0; p < ret.size(); p++) {26ret[p] = (bytes[p / 8] & (1 << (p % 8))) != 0;27}28return ret;29}31CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<Txid>* txids)32{33header = static_cast<const CBlockHeader&>(block);35std::vector<bool> vMatch;36std::vector<Txid> vHashes;38vMatch.reserve(block.vtx.size());39vHashes.reserve(block.vtx.size());41for (unsigned int i = 0; i < block.vtx.size(); i++)42{43const Txid& hash{block.vtx[i]->GetHash()};44if (txids && txids->contains(hash)) {45vMatch.push_back(true);46} else if (filter && filter->IsRelevantAndUpdate(*block.vtx[i])) {47vMatch.push_back(true);48vMatchedTxn.emplace_back(i, hash);49} else {50vMatch.push_back(false);51}52vHashes.push_back(hash);53}55txn = CPartialMerkleTree(vHashes, vMatch);56}58// NOLINTNEXTLINE(misc-no-recursion)59uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::vector<Txid> &vTxid) {60//we can never have zero txs in a merkle block, we always need the coinbase tx61//if we do not have this assert, we can hit a memory access violation when indexing into vTxid62assert(vTxid.size() != 0);63if (height == 0) {64// hash at height 0 is the txids themselves65return vTxid[pos].ToUint256();66} else {67// calculate left hash68uint256 left = CalcHash(height-1, pos*2, vTxid), right;69// calculate right hash if not beyond the end of the array - copy left hash otherwise70if (pos*2+1 < CalcTreeWidth(height-1))71right = CalcHash(height-1, pos*2+1, vTxid);72else73right = left;74// combine subhashes75return Hash(left, right);76}77}79// NOLINTNEXTLINE(misc-no-recursion)80void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, const std::vector<Txid> &vTxid, const std::vector<bool> &vMatch) {81// determine whether this node is the parent of at least one matched txid82bool fParentOfMatch = false;83for (unsigned int p = pos << height; p < (pos+1) << height && p < nTransactions; p++)84fParentOfMatch |= vMatch[p];85// store as flag bit86vBits.push_back(fParentOfMatch);87if (height==0 || !fParentOfMatch) {88// if at height 0, or nothing interesting below, store hash and stop89vHash.push_back(CalcHash(height, pos, vTxid));90} else {91// otherwise, don't store any hash, but descend into the subtrees92TraverseAndBuild(height-1, pos*2, vTxid, vMatch);93if (pos*2+1 < CalcTreeWidth(height-1))94TraverseAndBuild(height-1, pos*2+1, vTxid, vMatch);95}96}98// NOLINTNEXTLINE(misc-no-recursion)99uint256 CPartialMerkleTree::TraverseAndExtract(int height, unsigned int pos, unsigned int &nBitsUsed, unsigned int &nHashUsed, std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) {100if (nBitsUsed >= vBits.size()) {101// overflowed the bits array - failure102fBad = true;103return uint256();104}105bool fParentOfMatch = vBits[nBitsUsed++];106if (height==0 || !fParentOfMatch) {107// if at height 0, or nothing interesting below, use stored hash and do not descend108if (nHashUsed >= vHash.size()) {109// overflowed the hash array - failure110fBad = true;111return uint256();112}113const uint256 &hash = vHash[nHashUsed++];114if (height==0 && fParentOfMatch) { // in case of height 0, we have a matched txid115vMatch.push_back(Txid::FromUint256(hash));116vnIndex.push_back(pos);117}118return hash;119} else {120// otherwise, descend into the subtrees to extract matched txids and hashes121uint256 left = TraverseAndExtract(height-1, pos*2, nBitsUsed, nHashUsed, vMatch, vnIndex), right;122if (pos*2+1 < CalcTreeWidth(height-1)) {123right = TraverseAndExtract(height-1, pos*2+1, nBitsUsed, nHashUsed, vMatch, vnIndex);124if (right == left) {125// The left and right branches should never be identical, as the transaction126// hashes covered by them must each be unique.127fBad = true;128}129} else {130right = left;131}132// and combine them before returning133return Hash(left, right);134}135}137CPartialMerkleTree::CPartialMerkleTree(const std::vector<Txid> &vTxid, const std::vector<bool> &vMatch) : nTransactions(vTxid.size()), fBad(false) {138// reset state139vBits.clear();140vHash.clear();142// calculate height of tree143int nHeight = 0;144while (CalcTreeWidth(nHeight) > 1)145nHeight++;147// traverse the partial tree148TraverseAndBuild(nHeight, 0, vTxid, vMatch);149}151CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {}153uint256 CPartialMerkleTree::ExtractMatches(std::vector<Txid> &vMatch, std::vector<unsigned int> &vnIndex) {154vMatch.clear();155// An empty set will not work156if (nTransactions == 0)157return uint256();158// check for excessively high numbers of transactions159if (nTransactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT)160return uint256();161// there can never be more hashes provided than one for every txid162if (vHash.size() > nTransactions)163return uint256();164// there must be at least one bit per node in the partial tree, and at least one node per hash165if (vBits.size() < vHash.size())166return uint256();167// calculate height of tree168int nHeight = 0;169while (CalcTreeWidth(nHeight) > 1)170nHeight++;171// traverse the partial tree172unsigned int nBitsUsed = 0, nHashUsed = 0;173uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch, vnIndex);174// verify that no problems occurred during the tree traversal175if (fBad)176return uint256();177// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)178if (CeilDiv(nBitsUsed, 8u) != CeilDiv(vBits.size(), 8u))179return uint256();180// verify that all hashes were consumed181if (nHashUsed != vHash.size())182return uint256();183return hashMerkleRoot;184}