区块链与merkle tree

Merkle Tree

Merkle Tree 是由计算机科学家 Ralph Merkle 在很多年前提出的,并以他本人的名字来命名。通常也被称作Hash Tree,就是存储hash值的一棵树。Merkle树的叶子是数据块的hash值。非叶节点是其对应子节点串联字符串的hash。
merkle tree(变体例如 merkle patricia tree:MPT)广泛地应用于比特币,以太坊,fabric等区块链项目上;也广泛地应用于一致性验证,数据校验,数据同步等服务中。

比特币与merkle tree

SPV

完整的比特币数据库(也就是区块链)已截止本文超过 200 GB 。因为比特币的去中心化特性,网络中的每个节点必须是独立,自给自足的,也就是每个节点必须存储一个区块链的完整副本。随着越来越多的人使用比特币,这条规则使得开销非常大,所以不太可能每个人都去运行一个全节点。由于节点是网络中的完全参与者,它们负有相关责任:节点必须验证交易和区块。

另外,要想与其他节点交互和下载新块,也有一定的网络流量需求。中本聪的比特币原始论文中,对这个问题也有一个解决方案:简易支付验证(Simplified Payment Verification, SPV)。轻钱包并不保存完整的区块链,而是只保存每一个区块的区块头。区块体保存了完整的交易信息,而交易信息需要的存储量大部分都是交易头的千倍以上。所以,如果只保存交易头,就可以极大的减少本地客户端存储的区块链信息。

如果这个时候SPV要对某一个交易进行验证,而本地又没有这个交易的信息,那怎么验证呢?这时,区块头里面的merkle root,以及区块对应的merkle tree就要起作用了。

比特币用 Merkle tree来获取交易哈希,哈希被保存在区块头中,并会用于工作量证明系统。每个块都会有一个 Merkle 树,它从叶子节点(树的底部)开始,一个叶子节点就是一个交易哈希(比特币使用双 SHA256 哈希)。叶子节点的数量必须是双数,但是并非每个块都包含了双数的交易。因为,如果一个块里面的交易数为单数,那么就将最后一个叶子节点复制一份凑成双数。

Merkle 树的好处就是一个节点可以在不下载整个块的情况下,验证是否包含某笔交易。并且这些只需要一个交易哈希,一个 Merkle 树根哈希和一个 Merkle 路径。

验证交易真实性

在比特币网络中的交易,只有已经被记录到区块链,并且已经得到6个确认的,才被认为是真实的,只有基于这些真实交易发起的新交易(输入与输出的概念),才是合法的。
交易真实性前提:

  • 交易是否已被记录到区块链中
  • 交易所在的区块链是最长的一条,没有在分叉链上
  • 每个节点接收到一条交易广播时,要查询作为一笔新交易的输入的真实性
  • 矿工对交易进行打包之前,对所有的输入进行真实性验证

全节点: SPV会把该交易信息向一个全节点发送merkle block message的请求,全节点会利用传过来的交易信息在自己的区块链数据库上查询,得到交易对应的区块,此时可以获得该区块的merkle tree, 再通过遍历的方法把该交易的验证路径生成并发给SPV。

SPV 收到返回时,会把该交易的hash值和验证路径的hash值会做一次merkle校验,如果和可信的merkle root hash (从全节点对应的区块上获取)一致,则认为该交易是可信的。

例子:验证data1。 如图,验证路径为黄色节点,虚线部分是计算出的节点,然后和merkle root:0123比较,他们是一致的,所以data1是存在的,可信的。

MT

fabric与merkle tree

在fabric1.2中,block 结构中,blockHeader中的datahash把blockdata的bytes采用sha256得出,其中涉及到merkle tree暂时并没有实现。
在fabric0.6中的世界状态采用bucket tree来组织,但是在fabric1.0以后随着pbft一起删掉了。
在这里既然没有采用,就不在细述。

以太坊与merkle tree

以太坊中采用了Merkle tree 与 Patricia Tree,即MPT。这部分阅读以太坊源码后再进行分析。

Merkle Tree操作示例代码

package main

import (
    "crypto/sha256"
    "fmt"
)

type MerkleTree struct {
    RootNode *MerkleNode
}

type MerkleNode struct {
    Left  *MerkleNode
    Right *MerkleNode
    Data  []byte
}

func NewMerkleNode(left, right *MerkleNode, data []byte) *MerkleNode {
    mNode := MerkleNode{}
    if left == nil && right == nil {
        hash := sha256.Sum256(data)
        mNode.Data = hash[:]
    } else {
        var data []byte
        if right != nil {
            data = append(left.Data, right.Data...)
        } else {
            data = left.Data
        }
        hash := sha256.Sum256(data)
        mNode.Data = hash[:]
    }

    mNode.Left = left
    mNode.Right = right
    return &mNode
}

func NewMerkleTree(data [][]byte) *MerkleTree {
    var nodes []MerkleNode
    if data == nil {
        fmt.Print("args error")
    }
    if len(data)%2 != 0 {
        data = append(data, data[len(data)-1])
    }
    for _, idata := range data {
        node := NewMerkleNode(nil, nil, idata)
        nodes = append(nodes, *node)
    }

    for i := 0; i < len(data)/2; i++ {
        var fathernodes []MerkleNode
        if len(nodes) == 1 {
            break
        }
        for j := 0; j < len(nodes); j += 2 {
            if j+1 >= len(nodes) {
                node := NewMerkleNode(&nodes[j], nil, nil)
                fathernodes = append(fathernodes, *node)
            } else {
                node := NewMerkleNode(&nodes[j], &nodes[j+1], nil)
                fathernodes = append(fathernodes, *node)
            }
        }

        nodes = fathernodes
    }
    mTree := MerkleTree{
        RootNode: &nodes[0],
    }
    return &mTree
}

猜你喜欢

转载自blog.csdn.net/yunlilang/article/details/81636339