1. hash指针
用哈希指针代替了普通指针(B block chain is a linked list using hash pointers)
区块链第一个区块叫作创世纪块(genesis block) ,最后一个区块是最近产生的区块(most recent block),每一个区块都包含了指向前一个区块的hash指针 一个区块的hash指针算法是:是把前面整个区块的内容,包括里面的hash pointer,合在一起,取hash值。
这个数据结构的好处是,我只要保留最后一个hahs值,就可以检测出之前的区块任何一个的修改,无论哪里做了改动,最后的hash值都会产生变化。所以区块链是牵一发而动全身。所以比特币没有必要保留所有的区块内容,只需要保留最近的几千个区块,就可以方便查询,如果需要用到更早的区块,可以向系统中其他节点要区块。有些节点是恶意的,可以算出给到的区块的hash值,然后和当前保留区块的对比一下,不一样就是恶意的。
2.merkle tree
比特币每个区块通过hash指针连接在一起,每个区块的的数据结构是merkle tree,merkle tree是一个三层深度的二叉树,如下图:
merkle tree 最底层是一个个交易内容(data blocks)。
区块分为两部分内容,分别是块头和块身(block header,block body)。块头里有hash值,但不存储具体的交易内容,交易内容存在块身里边。
merkle tree 的作用:提供merkle proof。
比特币中的节点分为两类:全节点(保存整个区块的内容,即块头块身都有,有交易的具体信息)和轻节点(例如手机上的比特币钱包)(只有块头)
这时存在一个问题:如何向一个轻节点证明某个交易是写入区块链的? 这时需要用到merkle proof :找到交易所在的位置(最底行的其中一个区块),这时该区块一直往上到根节点的路径就叫merkle proof。
最上面一行是小型的区块链,该图展现的是一个区块的merkle tree,最下面一行是包含的交易。假设某个轻节点想知道图中黄色的交易,是否包含在了merkle tree里面。该轻节点没有包含交易列表,没有这颗merkle tree的具体内容,只有一个根哈希值。这时轻节点向一个全节点发出请求,请求证明黄色的交易被包含在这颗merkle tree里面的merkle proof。全节点收到这个请求之后,只需要将图中标为红色的这三个哈希值发给轻节点即可。有了这些哈希值之后,轻节点可以在本地计算出图中标为绿色三个哈希值。首先算出黄色交易的哈希值,即它正上方的那个绿的哈希值,然后跟旁边红色的哈希值拼接起来,可以算出上层节点绿色的哈希值。然后再拼接,再算出上层绿色哈希值,再拼接,就可以算出整棵树的根哈希值。轻节点把这个根哈希值和block header里的根哈希值比较一下,就能知道黄色的交易是否在这颗merkle tree里。
全节点在merkle proof里提供的这几个哈希值,就是从黄色的交易所在的节点的位置到树根的路径上用到的这些哈希值。轻节点收到这样一个merkle proof之后,只要从下往上验证,沿途的哈希值都是正确的即可。(验证时只能验证该路径的哈希值,其他路径是验证不了的,即该图中红色的哈希值是验证不了的)
这样是否不安全呢?假如黄色交易被篡改,它的哈希值发生了变化,那能不能调整旁边红色的哈希值,使得它们拼接起来的哈希值是不变的呢?不行,根据collision resistance,这是不可行的。
merkle proof可以证明merkle tree里面包含了某个交易,所以这种证明又叫proof of membership或 proof of inclusion。
对于一个轻节点来说,验证一个merkle proof 复杂度是多少?假设最底层有n个交易,则merkle proof 复杂程度是θ(log(n))