区块链-默克尔树(Merkle Tree)

Merkle Tree 也被成为 Hash Tree,见名思意,这种树其实就是用来存储 hash 值的一种树。关于hash我们在之前的文章已经说过了,对于一个输入,都有一个唯一的长度的固定的输出,且以我们目前的科技状况,无法找到两个不同的输入使得输出一样。
简单来说就是
y = H(x), y’ = H(x’)
我们无法找到 x != x’, 但 y = y’

区块链-默克尔树(Merkle Tree)_第1张图片

从以上这张图,我可以看出,我们有 n 个数据,分别对这个 n 个数据进行hash之后,可以得 n 个节点。 然后对 n 个节点进行两两配对,生成 n/2 个节点,直到只剩下一个单独的节点,也即根节点。 时间复杂度是 O(n),这里的 O(n) 是指做了 n 次 hash,树的高度是 log(n) + 1。

虽然 Merkle Tree的概念和实现都很简单,但是却相当有用。考虑一下以前的P2P网络,比如快播,在快播出来之前,我们下载软件都是要从某个源下载软件。这里有几个问题:
1. 以前的网络速度很慢
2. 只有一个源地址,大家都相互挤占资源
3. 源地址down掉之后,所有资源不可得

但是有了Merkle Tree之后,我们可以同时从多个节点下载数据块,只需要从可以信任的地址获取 hash值进行校验即可,这不仅减少了数据源的网络压力,同时也方便了用户。

我们再来看一下比特币是如何应用默克尔树,一下这张图是比特币的区块图

区块链-默克尔树(Merkle Tree)_第2张图片

看中间这个区块,矩形是区块头,包含了前一个节点的hash值(Prev Hash), 用于工作量证明的随机值(Nonce),区块时间戳(Timestamp),和默克尔树的根节点(Merkle Root)。

根据比特币的设计,它把所有的交易生成一棵默克尔树,然后节点可以根据自己身情况是否要保存整棵树,对于矿工来说,需要保存整个区块链的数据,然而这是一个相当大的数据,普通电脑的容量明显不够,这时候我们可以选择只保存区块头,也即只保存默克尔树的各节点,舍弃其它子节点,这将极大地减少存储容量(这个其实就是比特币轻量级钱包)。

附上用 node.js 实现的 Merkle Tree
P.S. 虽然我的本命是 c++,但是node.js用起来确实蛮爽的,核心代码才30行

/*
 * @Author: Lip Wang ([email protected]) 
 * @Date: 2018-04-07 19:52:07 
 */

const SHA256 = require("crypto-js/sha256");
const Queue = require("../utils/queue.js");

class Node {
  constructor(hash, left = null, right = null) {
    this.hash = hash;
    this.left = left;
    this.right = right;
  }
}

class MerkleTree {
  constructor(values) {
    this.tree = values instanceof Array ? this.generateTree(values) : null;
  }

  generateTree(values) {
    if (!(values instanceof Array)) {
      return null;
    }
    if (!values.length) {
      return this.tree;
    }

    let nodes = [];
    for (let i in values) {
      const hash = SHA256(String(values[i])).toString();
      nodes.push(new Node(hash));
    }
    while (nodes.length > 1) {
      let parents = [];
      for (let i = 0; i < nodes.length; ) {
        let node = null;
        if (i + 1 < nodes.length) {
          const hash = SHA256(nodes[i].hash + nodes[i + 1].hash).toString();
          node = new Node(hash, nodes[i], nodes[i + 1]);
        } else {
          const hash = SHA256(nodes[i].hash).toString();
          node = new Node(hash, nodes[i]);
        }
        parents.push(node);
        i += 2;
      }
      nodes = parents;
    }

    this.tree = nodes[0];
    return this.tree;
  }

//   displayTree(tree) {
//     if (!tree) return;
//     const queue = new Queue();
//     queue.push(tree);
//     while (!queue.isEmpty()) {
//       const item = queue.pop();
//       console.log(item.hash);
//       if (item.left) {
//         queue.push(item.left);
//       }
//       if (item.right) {
//         queue.push(item.right);
//       }
//     }
//   }
}

module.exports = exports = MerkleTree;

这里推荐一篇博文,非常详细地讲解了Merkle Tree
Merkle Tree(默克尔树)算法解析

你可能感兴趣的:(区块链)