如上图所示,每当一个stateObject有改动,亦即“账户”信息有变动时,这个stateObject对象会更新,并且这个stateObject会标为dirty,此时所有的数据改动还仅仅存储在map里。当IntermediateRoot()调用时,所有标为dirty的stateObject才会被一起写入trie。而整个trie中的内容只有在CommitTo()调用时被一起提交到底层。可见,这个map被用作本地的一级缓存,trie是二级缓存,底层是第三级,各级数据结构的界限非常清晰,这样逐级缓存数据,每一级数据向上一级提交的时机也根据业务需求做了合理的选择。
StateDB中账户状态的版本管理
StateDB还可以管理账户状态的版本。这个功能用到了几个结构体:journal,revision,先来看看UML关系图:
其中journal对象是journalEntry的散列,长度不固定,可任意添加元素。接口journalEntry存在若干种实现体,描述了从单个账户操作(账户余额,发起合约次数等),到account trie变化(创建新账户对象,账户消亡)等各种最小事件。revision结构体,用来描述一个‘版本’,它的两个整型成员jd和journalIndex,都是基于journal散列进行操作的。
上图简述了StateDB中账户状态的版本是如何管理的。首先journal散列会随着系统运行不断的增长,记录所有发生过的单位事件;当某个时刻需要产生一个账户状态版本时,代码中相应的是Snapshop()调用,会产生一个新revision对象,记录下当前journal散列的长度,和一个自增1的版本号。
基于以上的设计,当发生回退要求时,只要根据相应的revision中的journalIndex,在journal散列上,根据所记录的所有journalEntry,即可使所有账户回退到那个状态。
Ethereum里的账户 - stateObject
每个stateObject对象管理着Ethereum世界里的一个“账户”。stateObject有一个成员变量data,类型是Accunt结构体,里面存有账户Ether余额,合约发起次数,最新发起合约指令集的哈希值,以及一个MPT结构的顶点哈希值。
stateObject内部也有一个Trie类型的成员trie,被称为storage trie,它里面存放的是一种被称为State的数据。State跟每个账户相关,格式是[Hash, Hash]键值对。有意思的是,stateObject内部也有类似StateDB一样的二级数据缓存机制,用来缓存和更新这些State。
stateObject定义了一种类型名为storage的map结构,用来存放[]Hash,Hash]类型的数据对,也就是State数据。当SetState()调用发生时,storage内部State数据被更新,相应标示为”dirty”。之后,待有需要时(比如updateRoot()调用),那些标为”dirty”的State数据被一起写入storage trie,而storage trie中的所有内容在CommitTo()调用时再一起提交到底层。
State数据略显神秘,目前笔者尚未完全理解它的含义,在代码里,仅仅查到某些合约指令中会调用SetState(),来更新某个stateObject中的State数据。
小结
任何一个系统中,数据部分的占用空间,运行效率当然会影响到整体性能。如何简洁完整的呈现数据,并涵盖业务模型下的大大小小各种需求;如何高效的管理数据,使得插入、删除、查找数据更快速;如何在业务模块和底层之间安排面向业务的、接口友好的本地存储模块,使得内存占用更紧凑,提交和回退数据更加安全等等,都是值得全面思考的。从本文中,可以看到整个Ethereum系统的架构设计、代码实现上,对于以上各个话题都进行了诸多考量,值得同业者学习参考。
Block结构体主要分为Header和Body,Header相对轻量,涵盖了Block的所有属性,包括特征标示,前向指针,和内部数据集的验证哈希值等;Body相对重量,持有内部数据集。每个Block的Header部分,Body部分,以及一些特征属性,都以[k,v]形式单独存储在底层中。
BlockChain管理Block组成的一个单向链表,HeaderChain管理Header组成的单向链表,并且BlockChain持有HeaderChain。在做插入/删除/查找时,要注意回溯,以及中相应的增删。
Merkle-PatriciaTrie(MPT)数据结构用来组织管理[k,v]型数据,它设计了灵活多变的节点体系和编码格式,既融合了多种原型结构的优点,又兼顾了业务需求和运行效率。
StateDB作为本地存储模块,它面向业务模型,又连接底层,内部利用两极缓存机制来存储和更新所有代表“账户”的stateObject对象。
stateObject除了管理着账户余额等信息之外,也用了类似的两级缓存机制来存储和更新所有的State数据。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-69032-9.html
猪狗不如