Bitcoin 默克尔树 Vs Ether 默克尔帕夏特树
这个是Bitcoin的默克尔树,先看左侧,树的叶子结点存储的是区块中的每笔交易数据,记录了交易的详细信息,并生成对应的hash,例如 Alice 给 Bob 转账 20BTC 的交易hash就是 12c5,所有交易数据就这样生成各自对应的hash,并按照顺序依次排好,就构成了最低层的node,底层node的hash值再依次向上构建上层的node,由下至上构建出平衡二叉树,得到根节点root的hash值。
这个默克尔树有什么用呢?
- 保证交易数据的不可篡改。
严格来说是增加作恶的成本,使其付出的代价远大于收益。因为root 节点的 hash 值会放在区块的 header 中,并构成最终的区块 hash,也就意味着,如果某个攻击者想要篡改某笔交易,那么它需要重新计算默克尔树,然后按照 POW 机制计算对应区块的 hash值,即使它碰巧挖出了这个区块,但是其他诚实节点还是按照原交易进行挖矿,很有可能也挖出来了,所以现在区块链网络中可能同时存在2个被挖出来的区块,正常交易的区块 A 和 篡改交易的区块 A',但最终比特币网络要接纳哪个区块,还取决于基于这2个区块的各自的链的长度,也就意味着,攻击者还要赶紧去计算下个区块的hash,并在诚实节点之前完成,这个难度就又升级了,因为攻击者面对的是整个比特币网络除它之外所有的算力,它在这一轮的竞争中胜出的可能性就微乎其微了。
唯一胜出的方案,就是他至少要拥有全网51%的算力,也就是所谓的51%攻击,但基于目前的比特币网络中的节点和矿池数量,想要做到拉拢51%的诚实节点,只能说理论上可行,但你试试???
- 支持轻节点协议。
有了这个默克尔树,验证交易准确性变得非常简单。右图中攻击者把该笔交易改成了 Alice 给 Eve 转账 20BTC,这样这笔交易的 hash 值就变成了 4a2f,它再构建出的上层 node 的hash值就会跟原来的不一样,就可以认定这不是一笔合法的交易,甚至都不用看 root 节点。
接下来看下以太坊
以太坊中使用了类似的数据结构-MPT(Merkle Patricia Trees),默克尔帕特里夏树,这是默克尔树的增强版,所以Bitcoin里有的特性,在这里都有,而且比Bitcoin更优。以太坊区块的header节点有3个字段分别用到了MPT树状结构,分别是交易根、交易收据根、状态根,我们用状态根来说说具体优在哪里。
todo 增加图示
- 节省存储空间
状态就是每个地址及其对应的余额、nonce、合约代码(如果有的话)、合约中的状态变量(如果有的话),以太坊会把address地址作为key,另几个维度的信息作为value,通过RLP的编码方式进行序列化,这时只是个map还不是tree呢,接下来,利用map的key从上往下来构建tree结构,每个字符占据1个 node ,如果2个地址中有相同的前缀,那么会合成1个 node,也就是前缀压缩特性。以太坊中有数百万的EOA账户和智能合约账户,所以压缩的效果会很明显,也就节省了很大的存储空间。
比特币网络中的默克尔树是个平衡二叉树,它的每个节点都是hash,因为hash足够离散,所以hash值本身毫无规律可言;而以太坊中的是个压缩版的二叉树,它的每个节点是进行RLP编码后的address地址的一部分,因为不同的账户可能会有相同的部分,于是他们就会共用1个节点。比如账户A的地址为0x12ab,账户B的地址为0x12cd,那么他们就共用 0x12 这个节点;同样假如账户C的地址为0x34ef,没有跟任何一个账户地址有重复的部分,那他也不会形成 0x34 和 ef 这2个节点,而是直接压缩成 0x34ef 这一个节点,这样也会降低树的高度,提高查询效率,所以你会发现以太坊的默克尔帕特里夏树设计的非常优雅。
其实在合约账户中,合约的状态变量,也是采用的MPT结构,只不过这时的key就不再是合约的地址,而是状态变量在合约中的slot槽位,如果是复杂的状态变量,比如数组、map、string等,则是其中每个元素的slot作为key。
RLP (Recursive Length Prefix)编码:是以太坊中用于序列化和反序列化数据的编码方法。RLP编码在以太坊网络中用于数据传输,也用于存储数据。在以太坊的Merkle Patricia Trees (MPT)中,键(key)和值(value)都会被RLP编码。
对于交易根和交易收据根,每个交易(或收据)的键是其在交易列表中的索引,这个索引会被RLP编码后作为键。
对于状态根,每个账户的地址作为键,也会被RLP编码。
当然,这个结构虽然完美但并没有在交易根、交易收据根体现出来,因为这2个的key可压缩的概率并不大。
交易根(Transactions Root):每个交易的键是其在交易列表中的索引,通常是该交易在区块中的序号。索引被转化为HEX格式,并用作MPT的键。在大多数情况下,交易列表中的交易并不会有很多共享的前缀。
收据根(Receipts Root):交易收据的MPT中的键也是基于交易在区块中的位置。每个交易都会生成一个收据,这个收据在MPT中的键就是对应交易的索引。同样也很少有共享前缀。
不过,这并不妨碍MPT成为以太坊的一个重要进步。