Bitcoin中的数据结构

Hash链与Merkel Tree

Posted by Emo on April 7, 2022

比特币笔记

EMO’s Blog

基础结构

比特币是基于区块链的去中心化数字货币。区块链本质上就是一条通过hash指针连接起来的hash链。链上的每一个节点就是一个区块,第一个产生的区块被称为genesis block(创世区块),每个区块由两部分组成

  1. Block header
  2. Block body

Block header中主要保存一些小的字段信息

{

` `nVersion //比特币的版本号

` `hashPrevBlock //前一个区块的hash pointer,用于连接到上一个区块

` `hashMerkelRoot //交易树的根hash,后面会说到

` `nTime //交易产生的时间

` `nBits //交易的难度范围,会通过调整它来使出块时间保持一定程度的稳定

` `nNonce //幸运数字,POW阶段产生的,之后会说到

}

每个区块的的Hash pointer是由H(Block header)产生的,我们可以看到hashPrevBlock参与到了当前hash的计算当中,这就是整条链具备了传递性,被篡改的难度也被提高了。如果当前区块链的高度为n,而你想要篡改高度为2的区块,那么这意味着你需要篡改2~n的所有区块,才能使篡改生效。因为当你修改了一个区块后,指向这个区块的后一个区块的hashPrevBlock也需要相应的变更,又因为hashPrevBlock参与了这个区块的hash值计算,所以你需要对这个以及它后面所有区块的hash依次重新进行计算。

Block Body中则存储着交易树 (Merkel Tree) 等完整的结构与信息。

交易树/Merkel Tree

区块链是基于交易的账本,所以每个区块中需要存储的是一笔笔的交易信息,那用什么数据结构来维护交易信息呢?比特币中使用了Merkel Tree这个数据结构。Merkel Tree本质上一棵二叉树,但是每个交易只存储在叶子节点上,而其他的节点则记录了其子节点的hash值合并后的再依次进行hash后的hash值,即H( H(left child) + H(right child) )。而这个树的root的hash值便是block header中的hashMerkelRoot。

使用这种结构的目的是实现Merkel proof,即证明一个交易是否被写入了某一个区块。参与并连接到比特币网络中的节点主要分为两种,全节点和轻节点。全节点中包含着区块链的完整的信息,它能够通过查找block body中存储的交易来验证一个交易是否被写入了区块当中。但是作为一个轻节点,只有block header要怎么验证呢?如果直接向其他全节点询问,那么无法解决拜占庭问题,因为你询问的全节点有可能是恶意节点会告诉你假的信息。想要解决需要信息要怎么办呢?设想一下,如果我们能够验证全节点告诉我们的信息的真实性,那么不就能解决了吗。Merkel Tree的设计就是为了解决这个问题。如果交易以Merkel Tree的形式来存储的话,轻节点就可以让全节点返回需要验证的节点所在位置为起点往上到根节点的所有邻居节点的hash值。

以上图为例,上图是一个区块中的Merkel Tree,如果一个轻节点需要验证TX2是否被写入这个区块中,轻节点自身是拥有H2的,全节点只需要将{H1, H6}发送给轻节点,轻节点就可以通过H1+H2计算出H5,然后H5+H6计算出root hash,最后只需要验证计算出来的root hash是否和自己记录的block header里的hashMerkelRoot相等即可。我们可以发现只要全节点更改了任何一个信息,计算出来的root hash都不会与hashMerkelRoot的值相等,因此我们可以确保全节点没有对我们说谎。这就是所谓的Merkel Proof。

我们其实可以发现,Merkel Proof其实只有在全节点告诉你TX被写入了区块中的时候才能验证全节点是否说谎。也就是说如果TX在事实上已经被写入了区块中,但是全节点欺骗你说并没有被写入进去,这个时候其实你是无法检测到全节点是否说谎的。也就是说Merkel Proof只能够检测出假阳性(False Positive)和真阳性(True Positive)。

  • 假阳性(False Positive):告诉你写入了,但实际没有写入
  • 真阳性(True Positive):告诉你写入了,实际也写入了
  • 假阴性(False Negative):告诉你没写入,但实际写入了
  • 真阴性(True Negative):告诉你没写入,实际也没写入

{ % if page.mermaid % } { % endif % }