读 数据的呈现和组织,缓存和更新 笔记

能理解的简单记了一下

若以Block作切割,那么Transaction和Contract就是更小的粒度;所有交易或操作的结果,将以各个个体账户的状态(state)存在,账户的呈现形式是stateObject,所有账户的集合受StateDB管理

Root:StateDB中的“state Trie”的根节点的RLP哈希值。Block中,每个账户以stateObject对象表示,账户以Address为唯一标示,其信息在相关交易(Transaction)的执行中被修改。所有账户对象可以逐个插入一个Merkle-PatricaTrie(MPT)结构里,形成“state Trie”。

TxHash: Block中 “tx Trie”的根节点的RLP哈希值。Block的成员变量transactions中所有的tx对象,被逐个插入一个MPT结构,形成“tx Trie”。

ReceiptHash:Block中的 "Receipt Trie”的根节点的RLP哈希值。Block的所有Transaction执行完后会生成一个Receipt数组,这个数组中的所有Receipt被逐个插入一个MPT结构中,形成"Receipt Trie"。

Body可以理解为Block里的数组成员集合,它相对于Header需要更多的内存空间,所以在数据传输和验证时,往往与Header是分开进行的。

Block对象的唯一标识符,就是它的(RLP)哈希值。需要注意的是,Block的哈希值,等于其Header成员的(RLP)哈希值。

BlockChain结构体被用来管理整个区块单向链表,在一个Ethereum客户端软件(比如钱包)中,只会有一个BlockChain对象存在。同Block/Header的关系类似,BlockChain还有一个成员变量类型是HeaderChain, 用来管理所有Header组成的单向链表。当然,HeaderChain在全局范围内也仅有一个对象,并被BlockChain持有(准确说是HeaderChain只会被BlockChain和LightChain持有,LightChain类似于BlockChain,但默认只处理Headers,不过依然可以下载bodies和receipts)

BlockChain 相对于HeaderChain主要增多了Processor和Validator两个接口行为变量,前者用以执行所有交易对象,后者可以验证诸如Body等数据成员的有效性。

这里的hash就是该Block(或Header)对象的RLP哈希值,在代码中也被称为canonical hash


StateDB有一个trie.Trie类型成员trie,它又被称为storage trie或stte trie,这个MPT结构中存储的都是stateObject对象,每个stateObject对象以其地址(20 bytes)作为插入节点的Key;每次在一个区块的交易开始执行前,trie由一个哈希值(hashNode)恢复出来。另外还有一个map结构,也是存放stateObject,每个stateObject的地址作为map的key。那么问题来了,这些数据结构之间是怎样的关系呢?

每当一个stateObject有改动,亦即“账户”信息有变动时,这个stateObject对象会更新,并且这个stateObject会标为dirty,此时所有的数据改动还仅仅存储在map里。当IntermediateRoot()调用时,所有标为dirty的stateObject才会被一起写入trie。而整个trie中的内容只有在CommitTo()调用时被一起提交到底层数据库。可见,这个map被用作本地的一级缓存,trie是二级缓存,底层数据库是第三级,各级数据结构的界限非常清晰,这样逐级缓存数据,每一级数据向上一级提交的时机也根据业务需求做了合理的选择。

StateDB中账户状态的版本是如何管理的。首先journal散列会随着系统运行不断的增长,记录所有发生过的单位事件;当某个时刻需要产生一个账户状态版本时,代码中相应的是Snapshop()调用,会产生一个新revision对象,记录下当前journal散列的长度,和一个自增1的版本号。

基于以上的设计,当发生回退要求时,只要根据相应的revision中的journalIndex,在journal散列上,根据所记录的所有journalEntry,即可使所有账户回退到那个状态。

猜你喜欢

转载自blog.csdn.net/JIYILANZHOU/article/details/81221948
今日推荐