Merkle tree
cpp
#include <cstdlib>
#include <string>
#include <bitcoin/bitcoin.hpp>
BC_USE_LIBBITCOIN_MAIN
using namespace bc;
bc::hash_digest calculate_merkle_root(bc::hash_list &merkle);
int bc::main(int argc, char *argv[])
{
bc::cout << "测试 merkle_tree" << std::endl;
bc::hash_list tx_hashes{
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000000"),
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000011"),
bc::hash_literal("0000000000000000000000000000000000000000000000000000000000000022"),
};
bc::hash_digest merkle_root = calculate_merkle_root(tx_hashes);
bc::string right_hash = "d47780c084bad3830bcdaf6eace035e4c6cbf646d103795d22104fb105014ba3";
assert(right_hash == bc::encode_hash(merkle_root));
bc::cout << bc::encode_hash(merkle_root) << std::endl;
return 0;
}
/**
* 计算 merkle root
*/
bc::hash_digest calculate_merkle_root(bc::hash_list &merkle)
{
if (merkle.empty())
{
return bc::null_hash;
}
if (merkle.size() == 1)
{
return merkle[0];
}
// 如果不是偶数, 则将最后一个元素复制一份凑成偶数
if (0 != (merkle.size() & 1))
{
merkle.push_back(merkle.back());
}
assert(0 == (merkle.size() & 1));
bc::hash_list tmp_merkle;
for (auto it = merkle.begin(); it != merkle.end(); it += 2)
{
bc::data_chunk concat_data(bc::hash_size * 2);
auto concat = bc::make_unsafe_serializer(concat_data.begin());
concat.write_hash(*it);
concat.write_hash(*(it + 1));
//assert(concat. == concat_data.end());
bc::hash_digest new_root = bc::bitcoin_hash(concat_data);
tmp_merkle.push_back(new_root);
}
merkle = tmp_merkle; //size 变为原来的一半
return calculate_merkle_root(merkle); //继续递归, 当然可以用迭代代替
}