Merkle树是一种哈希二叉树,它是一种用作快速归纳和校验大规模数据完整性的数据结构
merkle数在bitcoin里有2个主要作用
2.1归纳一个区块里全部交易为一个32字节值hash值。
比特币使用Merkle树的方式进行验证,相对于哈希列表,Merkle树是一种哈希二叉树,它的明显的一个好处是可以单独拿出一个分支来(作为一个小树)对部分数据进行校验,更加高效。
我们回看下上面的区块结构图,区块体就包含这样一个Merkle树,Merkle树被用来归纳一个区块中的所有交易
2.2区块中缺少哪些交易,可以快速验证,复杂度在2log2(N)
当N个数据元素经过加密后插入Merkle树时,你至多计算2*log2(N)次就能检查出任意某数据元素是否在该树中,这使得该数据结构非常高效
3.1代码位置
bitcoin里merkle代码使用与移位<<和与&操作,代码不是很好理解
代码位于merkle.h/merkle.cpp里
3.2代码详解
入口函数,bitcoin在构建一个区块调用该函数计算merkle的根hash值
**uint256 BlockMerkleRoot(const CBlock& block, bool* mutated)**
{
std::vector leaves;
//获取一个区块交易的数量,也就是merkle的(调用resize设置vector大小,避免)
//避免在下面赋值需要重新分配内存
leaves.resize(block.vtx.size());
for (size_t s = 0; s < block.vtx.size(); s++)
{
leaves[s] = block.vtx[s]->GetHash(); //获取每一笔交易的hash值
}
return ComputeMerkleRoot(leaves, mutated);
}
uint256 ComputeMerkleRoot(const std::vector & leaves, bool* mutated)
{
//uint256继承模板类base_blob的特化base_blob<256>,base_blob<256>可以看做是对char[32]的一个封装类
//hash函数特点就是任何输入,hash后输出都是32字节
uint256 hash;
MerkleComputation(leaves, &hash, mutated, -1, nullptr);
return hash;
}
//merkle tree的根hash256计算(代码进行了简化,只保留根节点hash计算逻辑)
static void MerkleComputation(const std::vector & leaves, uint256* proot, bool* pmutated, uint32_t branchpos, std::vector * pbranch)
{
//如果没有叶子节点,
if (leaves.size() == 0)
{
if (proot) *proot = uint256();
return;
}
uint32_t count = 0;
/*
计算所有叶子节点的hash值计算,存储在inner数组
如果leaves.size()个数如果是2的幂次方,在下面第一个循环一次可获得根的hash值
,并且存储在2^k=leaves.size(),inner[k]的位置,假设有8个叶子节点
那么计算完 inner[3]就是根的hash值,8个叶子节点代码计算过程如下。代码65行
1.计算hash(ab) 存储在inner[1]
2.计算hash(cd) 存储在inner[2]
3.计算hash(ab+cd=N) 存储在inner[2] (代码83行 2,3步骤在一个循环执行)
4.计算hash(ef) 存储在inner[1],这是会覆盖步骤1
5.计算hash(gh) (5,6,7在一个循环连续执行,代码73)
6.计算hash(ef+gh=M)
7.计算hash(M+N) 存储在inner[3]
abcdefgh
/\
abcd efgh
/\ /\
ab cd ef gh
/\ /\ /\ /\
a b c d e f g h
*/
uint256 inner[32];
while (count < leaves.size())
{
uint256 h = leaves[count];
count++;
int level;
//count为偶数循环条件满足,奇数叶子节点hash先暂时存储在inner[0]
for (level = 0; !(count & (((uint32_t)1) << level)); level++)
{
//循环执行次数和count相关
//count作为二进制看,从右到左0的个数就是循环次数
//为什么有时候要执行多次,其实是和前面的hash节点在做拼接后做hash计算
//如果count=4(0100),会执行循环2次,第一次计算hash(cd),循环第二次计算就是hash(ab+cd)
CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
}
inner[level] = h;
}
int level = 0;
/*
这里用循环计算level分三种情况
1.count是2的幂 ,假设count=8,那么inner[2^3] = 8 ,inner[level]就是树根hash值
后面第二个循环不会被执行,函数返回root的hash。
abcdefgh == inner[3]
/\
abcd efgh
/\ /\
ab cd ef gh
/\ /\ /\ /\
a b c d e f g h
2.count不是2的幂并且是奇数,假设count=5,那么inner[0]存储的是最后一个节点hash值,
这个节点找不到配对节点来计算hash,只能复制一份和自己做hash。
abcdefee
/\
inner[1]==abcd efee
/\ /\
ab cd ef [ee]
/\ /\ /\
a b c d e [e] 复制一份和自己做hash(e+e)
3.count不是2的幂并且是偶数,假设count=6,level[1]==hash(ef),进入后面循环线执行hash(ef+ef)
,然后在执行hash(abcd+efef)
abcdefee
/\
abcd efef
/\ /\
ab cd ef [ef] 复制一份和自己做hash
/\ /\ /\
a b c d e f
*/
while (!(count & (((uint32_t)1) << level)))
{
level++;
}
//这里的level值参考上面说明
uint256 h = inner[level];
while (count != (((uint32_t)1) << level)) {
//当merkle树level层节点是奇数个,需要自己和自己算一次hash
CHash256().Write(h.begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
/*
//不管count是多少,计算出第一个大于count的2的幂的数
//如果count是6,计算结果是8
//如果count是7,计算结果是8
//如果count是13,计算结果是16
*/
count += (((uint32_t)1) << level);
level++;
//如果count不是2的幂的,下面循环不会被执行
while (!(count & (((uint32_t)1) << level)))
{
//和前面节点hash值拼接再次计算hash
CHash256().Write(inner[level].begin(), 32).Write(h.begin(), 32).Finalize(h.begin());
level++;
}
}
// Return result.
if (proot)
*proot = h;
}
老版本的merkle,这个很好理解
static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::vector & vMerkleTree)
{
vMerkleTree.clear();
vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
for (std::vector ::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it)
vMerkleTree.push_back((*it)->GetHash());
int j = 0;
bool mutated = false;
for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
//因为循环步骤是2,取一个最小值防止数组越界
int i2 = std::min(i+1, nSize-1);
if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
// Two identical hashes at the end of the list at a particular level.
mutated = true;
}
//hash计算2个字符串拼接的hash256
//从前到后,每次取相邻2个节点计算hash,并放入数组尾部
vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(),
vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end()));
}
j += nSize;
}
if (fMutated) {
*fMutated = mutated;
}
return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());
}