5.4 以太坊源码详解4

MPT(实现快速查找以节省存储空间) 
背景

  • Trie:用于快速检索的多叉树,查找速度快、但是需要耗费大量的存储空间
  • Patricia Trie:耗费的空间更小
  • Merkle Tree:Merkle树是一种用于快速验证内容完整性的数据结构,其基本原理是分别计算树的叶结点的hash值,然后把叶结点的hash值拼接在起,再计算hash作为其结点的hash值,依次向上直到根结点,根结点的hash值称为Merkle Root。 可以看出,如果想要获得相同的Merkle Root,所有结点的内容都必须相同,这样就可以来验证树的内容有没有被篡改

概念

  • MPT:MPT融合了3种数据结构,但是又有一些细微的差别。
  • MPT是用来检索字节数据的,因此是16叉树,分别代表0x0~0xF。

结构 
MPT定义4种结点类型:

  1. 空结点(NULL)
  2. 支结点(branch node):包含16个分支,以及1个value
  3. 扩展结点(extension node):只有1个子结点
  4. 叶子结点(leaf node):没有子结点,包含一个value

HP编码

  • MPT树中另外一个重要的概念是一个特殊的十六进制前缀(hex-prefix, 
    HP)编码,用来对key进行编码。因为字母表是16进制的,所以每个节点可能有16个孩子。因为有两种[key,value]节点(叶节点和扩展节点),引进一种特殊的终止符标识来标识key所对应的是值是真实的值,还是其他节点的hash。如果终止符标记被打开,那么key对应的是叶节点,对应的值是真实的value。如果终止符标记被关闭,那么值就是用于在数据块中查询对应的节点的hash。无论key奇数长度还是偶数长度,HP都可以对其进行编码。最后我们注意到一个单独的hex字符或者4bit二进制数字,即一个nibble。
  • HP编码很简单。一个nibble被加到key前(下图中的prefix),对终止符的状态和奇偶性进行编码。最低位表示奇偶性,第二低位编码终止符状态。如果key是偶数长度,那么加上另外一个nibble,值为0来保持整体的偶特性。

源码分析

  • 以太坊中的MPT的实现源代码:trie/trie.go以及trie/node.go。trie.go主要实现struct 
    Trie以及MPT树的各种操作:查询,添加,删除。node.go实现了四种节点以及从持久化数据库中解析node。理解了Node的实现,Trie的实现很容易理解。有关MPT中的四种节点,node.go的实现如下:
    type (
        // 分支节点
        fullNode struct {
            Children [17]node // Actual trie node data to encode/decode (needs custom encoder)
            flags    nodeFlag
        }
        // 实现叶子节点和扩展节点
        shortNode struct {
            Key   []byte
            Val   node
            flags nodeFlag
        }
        hashNode  []byte
        valueNode []byte
    )
    // 每个节点的哈希信息
    type nodeFlag struct {
        hash  hashNode // cached hash of the node (may be nil)
        gen   uint16   // cache generation counter
        dirty bool     // whether the node has changes that must be written to the database
    }
    总结
  • MPT是以太坊用来存储“状态”的数据结构,综合了Trie,Patrica Trie以及Merkletree的优点
  • MPT的key是用HEX编码,在持久化存储时,会转换为HP编码。以太坊的go语言实现中,用fullNode表达分支节点,用shortNode表示叶子节点和扩展节点。

 

  • 学院Go语言视频主页
    https://edu.csdn.net/lecturer/1928

  • 清华团队带你实战区块链开发

  • 扫码获取海量视频及源码   QQ群:721929980

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