
6.5 Merkle Patricia树
Merkle Patricia树(MPT)是一种经过改良的、融合了默克尔树和前缀树两种树结构优点的数据结构,是以太坊中用来组织管理账户数据、生成交易集合哈希的重要数据结构。在以太坊每个区块头中,存有三个根值:StateRoot(用于存储所有账户状态)、TransactionsRoot(用于存储区块中的交易数据)、和ReceiptsRoot(用于存储区块中的接收账户数据),它们都使用了MPT数据结构。所有在以太坊中使用的默克尔树实际上都是MPT。
MPT是默克尔树和前缀树的结合,其结构具有以下特性:
高安全性:每个唯一键值对唯一映射到根的哈希值。难以破解(除非攻击者有2128的算力)。
易修改性:增、删、改键值对的时间复杂度是对数级别。
MPT在以太坊数据结构中发挥的作用:
存储任意长度的key-value键值对数据。
提供了一种快速计算所维护数据集哈希标识的机制。
提供了快速状态回滚的机制。
提供了一种称为默克尔证明的证明方法,进行轻节点的扩展,实现简单支付验证。
6.5.1 快速状态回滚
在公链的环境下,采用POW算法可能会造成分叉而导致区块链状态进行回滚。在以太坊中,由于出块时间短,这种分叉的概率很大,区块链状态回滚的现象很频繁。所谓的状态回滚指的是:
1)区块链内容发生了重组织,链头发生切换。
2)区块链的全局状态(账户信息)需要进行回滚,即对之前的操作进行撤销。
MPT提供了一种机制,可以在区块发生碰撞时零延迟地完成全局状态的回滚。这种优势的代价就是需要浪费存储空间去冗余地存储每个节点的历史状态。
每个节点在数据库中的存储都是值驱动的。当一个节点的内容发生了变化,其哈希相应改变,而MPT将哈希作为数据库中的索引,也就实现了对于每一个值在数据库中都有一条确定的记录。MPT是根据节点哈希来关联父子节点的,因此,每当一个节点的内容发生变化,最终对于父节点来说,改变的只是一个哈希索引值;父节点的内容也由此改变,产生了一个新的父节点,递归地将这种影响传递到根节点。最终,一次改变对应创建了一条从被改节点到根节点的新路径,而旧节点依然可以根据旧根节点通过旧路径访问得到。
6.5.2 简单支付验证(SPV)
简单支付验证,即Simple Payment Verification,简称SPV。SPV的目标是不运行全节点也可以验证支付(交易的存在性检查和交易是否重号的检查)。
SPV充分利用了区块的结构信息及默克尔树的强大搜索能力,从而能实现对交易信息的快速定位。SPV节点是一种轻节点,节点只需要维护链中所有的区块头信息(一个区块头的大小通常为几十个字节,普通的移动终端设备完全能够承受),在验证交易是否存在时不保存所有交易,也不会下载整个区块,只是保存区块头。它使用认证路径或者默克尔路径来验证交易存在于区块中,而不必下载区块中所有的交易。
默克尔证明,即一个轻节点向一个全节点发起一次证明请求,询问全节点在完整的默克尔树中是否存在一个指定的节点;全节点向轻节点返回一个默克尔证明路径,由轻节点进行计算,验证其存在性。
SPV强调的是验证支付,不是验证交易。这两个概念是不同的。验证支付比较简单,只需要判断用于支付的那笔交易是否被验证过,以及得到网络多少次确认(即有多少个区块叠加)。而验证交易则复杂得多,需要验证账户余额是否足够支出、是否存在双重支付、交易脚本是否通过等问题,一般这个操作是由全节点的矿工来完成。