通过源码学习比特币--构造merkle树

Merkle 树是一种哈希二叉树, 从数据结构角度说 它是一个完美二叉树(perfect binary tree), 在比特币中用来归纳区块所包含的所有交易

1. merkle 树的构建

假如某区块包含4个交易TxA TxB TxC TxD, 其构建的merkle树由下图所示:
通过源码学习比特币--构造merkle树_第1张图片

  • Hash() 函数实际是进行两次的SHA256运算
    Hash(TxA) == SHA256(SHA256(TxA))

上例中由于交易个数正好是2^2个, 所以可以构建出一个perfect二叉树(节点数为 2^n-1)
如果交易的个数是3个, 则会把最后一个交易的哈希值复制一份,从而构建perfect 二叉树。

构造merkle树的源码(原始版0.1.0)如下:

    uint256 BuildMerkleTree() const
    {
        vMerkleTree.clear(); //vMerkleTree的类型为vector
        foreach(const CTransaction& tx, vtx) //vtx:保存块中所有交易的vector
            vMerkleTree.push_back(tx.GetHash()); //先把所有交易的hash值(叶子节点) push到 vMerkleTree
        int j = 0; //存放merkle树的每层第一个节点在数组中的位置
        for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)//第一重循环构造树的层 nSize为每层节点个数
        {
            for (int i = 0; i < nSize; i += 2)//第二重循环构建每层的节点
            {
                int i2 = min(i+1, nSize-1);//i2为i节点后面的节点,当到最后一个节点时,如果nsize为奇数 则i2 = 最后一个节点
                vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
                                           BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));//计算第i节点和i2节点hash连接后的hash值
            }
            j += nSize; //每构建一层,j就增加本层节点个数 从而"指向"下一层第一个节点
        }
        return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); //返回merkle根
    }
  • 由此可见 merkle树把所有节点从第0层开始按从左到右的顺序 存储在vector中, 一直到根节点,因此vMerkleTree的最后一个item就是merkle树的根

2. 通过merkle branch 验证一个交易是否包含在某个区块中

merkle branch是merkle tree的一条路径(由merkle树节点组成),每一个交易都对应一个merkle branch

下图是交易A对应的merkle branch “BF”:
通过源码学习比特币--构造merkle树_第2张图片

通过交易的hash值 和其merkle branch可以很容易计算出merkle树的根,用计算出的merkle 根和区块头中记录的merkle根比较,如果相等 就说明次交易存在于这个区块中

下面是构造merkle branch的源码:

vector CBolck::GetMerkleBranch(int nIndex) const
    {
        if (vMerkleTree.empty())
            BuildMerkleTree();
        vector vMerkleBranch;
        int j = 0; //j指向每一层的起点
        for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
        {
            int i = min(nIndex^1, nSize-1);// nIndex:交易在vTx中的索引
            vMerkleBranch.push_back(vMerkleTree[j+i]);
            nIndex >>= 1;
            j += nSize;
        }
        return vMerkleBranch;
    }

交易的merkle branch存放在交易结构中:

class CMerkleTx : public CTransaction
{
public:
    uint256 hashBlock;
    vector vMerkleBranch;
    int nIndex;

    // memory only
    mutable bool fMerkleVerified;
// 方法省略
};

验证函数 CheckMerkleBranch :

static uint256 CBlock::CheckMerkleBranch(uint256 hash, const vector& vMerkleBranch, int nIndex)
    {
        if (nIndex == -1)
            return 0;
        foreach(const uint256& otherside, vMerkleBranch)
        {
            if (nIndex & 1)
                hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
            else
                hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
            nIndex >>= 1;
        }
        return hash; //返回的是计算出来的merkle根
    }

验证CheckMerkleBranch方法返回的结果是否和CBlock中对应的merkle根的值一样,即如下面代码所示:

if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pBlock->hashMerkleRoot)
            return 0;

你可能感兴趣的:(blockChain)