以太坊是由多个组成部分构成的。这篇文章旨在解构以太坊,使你能更深入理解它的数据存储层。我们将介绍区块链中“状态”的概念,并探究帕特里夏前缀树(Patricia Trie)数据结构的理论依据,利用 Google 的 leveldb 数据库来阐释以太坊中前缀树的应用。本文同时和一篇手把手学习指引相关联,它能指导你安装并配置好自己的以太坊私有网络(包括挖矿)。学习之后你将能够执行交易,并且探索以太坊的“状态”是如何根据诸如交易这样的活动而改变的。
1
什么是区块链“状态”?
比特币的“状态”是通过网络中全局的未使用交易输出(UTXO)来刻画的。比特币网络中价值的传递通过交易来进行,更准确地说,一个比特币用户能使用一个或多个 UTXO 来创建一笔交易,所消耗的 UTXO 将作为交易的输入。
对 UTXO 更详尽的介绍不在本文的讨论范围内,然而在接下来的数个段落中,我们将不断提及这一概念,来指出比特币和以太坊之间基础实现上的差异。
接下来的两个比特币例子将指出比特币 UTXO 模型和以太坊世界状态概念之间的不同之处。
首先,比特币的 UTXO 不能被拆分消耗。如果一个比特币用户想要花费 0.5 个比特币(他手上只有一个价值 1 比特币的 UTXO),他必须显式地将赋予 0.5 个比特币转账地址(转给自己)作为找零。如果他们没有设置自我找零,那么 0.5 个比特币就会作为矿工打包交易的奖励转给矿工。
第二点,在一个最底层的角度来说,比特币并不保存用户的账户余额。在比特币中,用户仅仅在某一给定时间点掌握着一到多个 UTXO 的私钥。尽管数字钱包设计得好像比特币区块链能自动保存和管理用户的余额等等,但实际上不是这样的。
用户的账户余额在比特币网络中是一种抽象的概念,事实上一个用户的余额是他所控制的每一个 UTXO (用户保管着对应的私钥)价值的和。用户所使用的私钥能对每一个 UTXO 进行签名和消费。
UTXO 系统在比特币网络中运行良好,某种程度上要归功于数字钱包能完成绝大多数与交易相关的工作,包括但不限于以下几点:
a) 操作 UTXO
b) 保存私钥
c) 设置交易费用
d) 提供找零地址
e) 统计 UTXO (显示可用余额、转帐中的数额以及总余额)
有趣的是,一个非确定性钱包(如上图中的比特币核心钱包)的备份仅仅提供 UTXO 的快照(在该时间点)。只要用户执行了任何交易(发送或接收),他们所生成的原始备份就过期了。
总结来说,我们知道:
-
比特币区块链不保存账户余额
-
比特币钱包保存 UTXO 的私钥
-
当被包含在某一条交易中时,整个 UTXO 就被使用掉了(在有些找零场景中,原来 UTXO 中的价值会被新的 UTXO 承载)
和上述比特币网络不同,以太坊世界状态已经能管理账户余额以及更多信息了。以太坊中的状态并不是一种抽象的概念,它是以太坊的基础层协议。正如黄皮书 [1] 中所提及的,以太坊是一个基于交易的“状态”机。基于所有交易的状态机概念就这样被构建出来。
让我们从头开始捋一捋,和其他区块链一样,以太坊区块链是由创世区块开始的。从这个起点开始(创世状态在 0 区块高度),诸如交易、合约以及挖矿的活动会持续不断地改变以太坊区块链的状态。在以太坊中,账户余额(存储在状态树中)随每一次交易进行所发生的改变就是这样一个例子。
值得留意的是,像账户余额这样的数据并不直接保存在以太坊区块链的区块中。区块中只保存交易树、状态树和收据树的根节点哈希值。其存储结构如下图所示。
从上图中可以注意到,存储树(所有智能合约数据存储的位置)的根节点哈希实际上指向了状态树,从而间接指向了区块链。接下来我们将深入探讨这一部分更细节的内容。
以太坊中存在两种截然不同的数据类型:永久数据和暂存数据。交易就是永久数据的一个例子。一旦一个交易被确认,它就将永久地被记录在交易树结构中,并且无法篡改。而某一个特定以太坊账户的余额则是暂存数据的例子。账户地址的余额存储在状态树中,并且每当接收到和该账户有关的交易时,该余额都会改变。将挖矿确认后的交易这样的永久数据和账户余额这样的暂存数据分开管理是有意义的。以太坊使用前缀树这种数据结构(上图所示结构)来管理数据,那么接下来我们介绍一下什么是前缀树。
2
前缀树
前缀树是众所周知用于存储有序字符串的一种数据结构。以太坊特别采用了一种被称为“检索用文字数字编码的信息的实用算法”(Practical algorithm to retrieve information coded in alphanumeric,缩写为 PATRICIA,下文音译“帕特里夏”)。帕特里夏树的主要优势在于它简缩的存储。接下来我们对比标准(传统)前缀树和帕特里夏前缀树之间工作原理的不同。