- 通过阅读代码理解Merkle Trees的结构,代码地址C++ implementation of a self balancing merkle tree
主要数据结构
节点Node
#ifndef NODE_H
#define NODE_H
#include <string>
struct Node {
std::string hash;
Node *left;
Node *right;
Node(std::string data);
};
#endif /* NODE_H */
MerkleTree
#ifndef MERKLE_TREE_H
#define MERKLE_TREE_H
#include "node.h"
#include "picosha2.h"
#include "misc.h"
#include <vector>
#include <string>
struct MerkleTree {
Node* root;
MerkleTree(std::vector<Node*> blocks);
~MerkleTree();
void printTree(Node *n, int indent);
void deleteTree(Node *n);
};
#endif /* MERKLE_TREE_H */
MerkleTree(std::vector<Node*> blocks)
- 构造函数
MerkleTree(std::vector<Node*> blocks)
将相邻的节点配对,并将它们的哈希值连接起来后进行哈希,生成新的父节点。如果节点数量为奇数,最后一个节点将不配对,直接加入 nodes 向量。
MerkleTree::MerkleTree(std::vector<Node*> blocks) {
std::vector<Node*> nodes;
while (blocks.size() != 1) {
printNodeHashes(blocks);
for (unsigned int l = 0, n = 0; l < blocks.size(); l = l + 2, n++) {
if (l != blocks.size() - 1) { // checks for adjacent block
nodes.push_back(new Node(hash_sha256(blocks[l]->hash + blocks[l+1]->hash))); // combine and hash adjacent blocks
nodes[n]->left = blocks[l]; // assign children
nodes[n]->right = blocks[l+1];
} else {
nodes.push_back(blocks[l]);
}
}
std::cout << "\n";
blocks = nodes;
nodes.clear();
}
this->root = blocks[0];
}
过程图示
- 初始状态
- 假设有四个叶子节点,它们的哈希值分别是
H1
,H2
,H3
,H4
。
叶子节点:
H1 H2 H3 H4
-
第一轮合并
-
将相邻的叶子节点配对并计算新的哈希值:
-
左边的两个节点
H1
和H2
合并,得到一个新的哈希值H12
。 -
右边的两个节点
H3
和H4
合并,得到一个新的哈希值H34
。
中间节点:
H12 H34
/ \ / \
H1 H2 H3 H4
-
第二轮合并
-
将中间节点再次配对,计算新的哈希值:
-
将
H12
和H34
合并,得到根节点H1234
。
根节点:
H1234
/ \
H12 H34
/ \ / \
H1 H2 H3 H4
main.cpp运行过程
1. 创建叶子节点
- 计算并存储 多个字符串的哈希值作为叶子节点。
std::vector<Node*> leaves;
: 创建一个Node*
类型的动态数组leaves
,用来存储叶子节点。
//create sample data
leaves.push_back(new Node(hash_sha256("abcdefg")));
leaves.push_back(new Node(hash_sha256("qwerty12345")));
leaves.push_back(new Node(hash_sha256("!@(@#)E&")));
leaves.push_back(new Node(hash_sha256("ajosdhuhsdioa adsijd asjiod q9p0ad a.")));
leaves.push_back(new Node(hash_sha256("test01234")));
leaves.push_back(new Node(hash_sha256("7846546521")));
leaves.push_back(new Node(hash_sha256("asd970123+_?>?< f")));
leaves.push_back(new Node(hash_sha256("op_) 4654asd21")));
leaves.push_back(new Node(hash_sha256("12893 d970123+_qweawdf")));
2.构建 Merkle 树
MerkleTree *hashTree = new MerkleTree(leaves);// 创建一个 MerkleTree 对象 hashTree,并将 leaves 作为参数传递给构造函数。将根据 leaves 向量构建 Merkle 树。
std::cout << hashTree->root->hash << std::endl;// 输出树的根节点的哈希值
hashTree->printTree(hashTree->root, 0);// 调用 printTree 方法打印整个树的结构,从根节点开始,深度为 0。
3.释放内存
// 遍历 leaves 向量并删除每个Node对象,释放动态分配的内存。
for (unsigned int k = 0; k < leaves.size(); k++) {
delete leaves[k];
}
delete hashTree; // 删除 hashTree 对象,释放动态分配的内存。
辅助函数
include/misc.h
主要进行Hash计算,其中用于计算哈希函数的语句#include "picosha2.h"
和std::string hash_hex_str = picosha2::hash256_hex_string(src_str);
,作者使用了项目a header-file-only, SHA256 hash generator in C++