助力软件开发企业降本增效 PHP / java源码系统,只需一次付费,代码终身使用! 广告
## 以太坊状态数据库 StateDB ### 为什么有状态数据库 即使在以太坊早期,当以太坊运行三个月后,以太坊客户端的本地文件夹存储已膨胀到惊人的 10 到40 GB。 截止到区块高度9001290,一个保留所有状态的以太坊归档节点,需要占用 216 GB 空间。如果说这些状态全部记录在区块链上,那么,这会是一个噩梦。 这会使得物联网设备、个人笔记本、手机等微设备无法使用以太坊客户端,会导致网络节点数量下降和影响用户使用。因此这些状态并非直接存储在区块链上,而是将这些状态维护在默克尔前缀树中,在区块链上仅记录对应的树 Root 值。使用简单的数据库来维护树的持久化内容,而这个用来维护映射的数据库叫做 StateDB。 ### 状态数据库存储什么内容 首先,以太坊中有两种级别的状态,一个是顶级的世界状态,另一个是账户级的账户状态。账户状态中存储账户信息: 1. nonce: 这个值等于由此账户发出的交易数量,或者由这个账户所创建的合约数量(当这个账户有关联代码时)。 2. balance: 表示这个账户账户余额。 3. storageRoot: 表示保存了账户存储内容的 MPT 树的根节点的哈希值。 4. codeHash: 表示账户的 EVM 代码哈希值,当这个地址接收到一个消息调用时,这些代码会被执行; 它和其它字段不同,创建后不可更改。如果 codeHash 为空,则说明该账户是一个简单的外部账户,只存在 nonce 和 balance。 在以太坊中不止一颗默克尔树,所有账户状态通过以账户地址为键,维护在表示世界状态的树中。所有账户也存在一颗表示此账户的存储数据的树,此树是独立唯一的。 通过账户地址便可以从世界状态树中查找到该账户状态(如账户余额),如果是合约地址,还可以继续通过 storageRoot 从该账户存储数据树中查找对应的合约信息(如:拍卖合约中的商品信息)。 至于为什么使用默克尔树来维护状态,将在后续文章中讲解。 ### StateDB是如何管理状态的 从程序设计角度,StateDB 有多种用途: 1. 维护账户状态到世界状态的映射。 2. 支持修改、回滚、提交状态。 3. 支持持久化状态到数据库中。 4. 是状态进出默克尔树的媒介。 实际上 StateDB 充当状态(数据)、Trie(树)、LevelDB(存储)的协调者。 ### StateDB持久化 在区块中,将交易作为输入条件,来根据一系列动作修改状态。 在完成区块挖矿前,只是获得在内存中的状态树的 Root 值。 StateDB 可视为一个内存数据库,状态数据先在内存数据库中完成修改,所有关于状态的计算都在内存中完成。 在将区块持久化时完成有内存到数据库的更新存储,此更新属于增量更新,仅仅修改涉及到被修改部分。 ![](https://img.kancloud.cn/df/e2/dfe2d2023a3153b139d1751a243e73dc_1720x1758.png) 如上图所示,上半部分均属于内存操作,仅仅在`stateDB.Commit()`时才将状态通过树提交到 leveldb 中。 ### StateDB如何校验数据 在轻节点中,因为本地并不存储状态数据,但又必须校验某数据的合法性,这依赖于默克尔树的校验。 StateDB 仅提供数据的读取实现。