3. 账户数据

之前提及的区块链数据,其实可以总结为是合约调用信息的流水集合。而智能合约在运行过程中,需要读/写合约状态数据。接下来就介绍这部分数据的组织结构。

由于hyperchain需要兼容EVM(Ethereum Virtual Machine),而EVM与以太坊的账户体系有着较强的耦合性,因此,hyperchain的state是在以太坊的基础上,做了一系列的改造及优化得到。

账户类别

与以太坊一样,hyperchain中的账户也可以分为两类:

  • 外部账户:外部账户的私钥由用户自己控制,可以主动发起交易,且这类账户不包含智能合约代码
  • 合约账户:合约账户包含一段可执行的智能合约代码,且有自己的存储空间用来存储自身的状态变量。该智能合约的运行可以由外部账户发起交易进行触发,也可以由其他合约“主动调用”进行触发。

虽然两类账户在逻辑上有所区别,但是共享一套定义:

一个账户的元数据包括以下字段:

  • 账户地址(20字节,由哈希函数根据一定的输入产生,不考虑哈希冲突的情况下,不会有两个相同地址的账户);
  • 余额:该余额表示该账户所拥有的hyperchain平台的token个数,这类token可以通过智能合约进行操控,也可以通过发起普通交易转账进行交易;
  • 状态变量(存储空间)哈希标识:一个合约账户,需要存储其所有的状态变量,一个用于表示这些状态变量的哈希值被存储在该字段;
  • 合约代码哈希:智能合约代码哈希标识;
  • 状态:合约状态,普通、冻结等;
  • 部署时间:若该账户为合约账户,则会记录该账户第一次被部署的时间点;
  • 创建者地址:若该账户为合约账户,则会记录该账户的创建者信息;
  • 已部署的合约地址列表:若该账户为外部账户,则会记录该账户部署的所有合约账户的地址;

3. 账户数据 - 图1

除了以上这些”简短”的数据被放置在账户元数据里,还有(1)合约源码(2)状态变量这些需要大量存储空间的数据被直接存储,在元数据中只存储这类数据的哈希值。

合约的状态变量,其实是一系列的kv键值对。在hyperchain中,每个合约账户,都会有一棵bucket tree,专门用来计算该合约的状态变量哈希。每次执行一笔交易,修改一系列状态变量,从底层来看,其实就是更新了一批kv对,而这些修改集刚好可以作为bucket tree的输入,以便快速地计算“新”的状态变量哈希。

账户集

3. 账户数据 - 图2

hyperchain将每一个账户的元数据进行序列化,将序列化得到的二进制作为一个账户的内容。

所有的账户数据,最终可以转换成一系列的kv对,key为该账户的地址,value为元数据序列化的内容。

对于账户集,会有一棵全局级别的bucket tree进行账户数据的哈希计算,示意图如上所示。每个账户数据仅作为bucket tree中的一条数据项,不断进行哈希计算,最终生成一个根节点,该节点的哈希值(merkle root)便是整个账户集的哈希标识。

该哈希值作为整个账户集的状态表示,不仅是共识阶段比较的依据之一,之后更是会被记录在区块头中。

原子性

hyperchain利用底层数据库leveldb提供的batch来保障账本的原子性。hyperchain采用rbft作为共识算法,因此整个处理流程会分成3阶段来完成。在执行阶段,所有对账本的改动会预先保存在一个leveldb的batch中;当本次执行的结果得到了足够多节点的认可,会从缓存中取出该batch,将所有的修改落盘。