美文网首页码农的世界深入浅出golang
以太坊 Block 、StateDB 与 Trie 的关系

以太坊 Block 、StateDB 与 Trie 的关系

作者: cc14514 | 来源:发表于2019-07-04 20:32 被阅读56次

StateDB 用法与结构

以太坊是基于账户体系实现的,块通过 parentHash 链在一起,每个块都包含若干交易,每个交易都包含账户 from 和 to(部署合约时除外),全部的账户凑在一起就是组成了 StateDB,每个块的 StateDB 都用一颗叫做 Trie 的树来组织账户信息,具体结构如下图:

BlockChain

保存账户信息的 StateDB 通常会存储在磁盘上,通过 Block.StateRoot 来进行加载,StateRoot 是树根,也是 leveldb 中的一个 key, 这个根只对应当前块的交易相关的账户信息,value 是这棵树的全部叶子节点,加载的时候会用叶子节点来构建下图中的树型结构

StateDB

智能合约的地址也被当作账户管理,当 Account 为一个智能合约时,那么这个 stateObject 也会包含一颗树,用来保存智能合约的最新状态信息,这些信息是每次执行 evm 中 SSTORE 这个指令时的输入信息,key 是合约的变量名,value 是最新值,这棵树的加载过程与上图中的过程完全一致

stateObject

StateDB 的工作方式

用最少的代码和最简单的例子说明 StateDB 的主要工作原理与过程

  • StateDB 的结构定义
type StateDB struct {
    db   Database
    trie Trie
    stateObjects      map[common.Address]*stateObject
    stateObjectsDirty map[common.Address]struct{}
    dbErr error
    refund uint64
    thash, bhash common.Hash
    txIndex      int
    logs         map[common.Hash][]*types.Log
    logSize      uint
    preimages map[common.Hash][]byte
    journal        *journal
    // 由 snapshot id 和 journal 长度组成,用于回滚
    validRevisions []revision
    // 下一个可用的 snapshot id
    nextRevisionId int
    lock sync.Mutex
}

*StateDB 的关键方法

func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) 
func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) 
func (s *StateDB) Finalise(deleteEmptyObjects bool) 

通过上面的三个方法可以演示整个 statedb 的操作流程
当执行 AddBalance 方法会设置 addrstateObject.Account.Balance += amount ,这时 addr 对应的 stateObject 会被放在 StateDB.stateObjects 中缓存起来,
当执行 Commit 方法时,会将 StateDB.stateObjects 中的数据构建成一颗默克尔树存放在 StateDB.trie 中,修改数据时会产生 journal 日志,为了方便出错时的回滚,
当执行 Finalise 方法时会删除 journal 刷新 stateObjecttrie.root (如果 stateObject 存在 trie)

执行到此时树的结构已经确定,最终的树根也已经确定,但是在以太坊中数据此时还没有进入数据库
为了提高效率StateDB对数据做了缓存处理,大部分时间都是放在内存中的,StateDB.db 是 state.Database 接口的实现,定义如下:

// Database wraps access to tries and contract code.
type Database interface {
    // blockchain 的 树,root == block.stateRoot
    OpenTrie(root common.Hash) (Trie, error)
    // account 的 树,addrHash == account.address
    OpenStorageTrie(addrHash, root common.Hash) (Trie, error)
    ......
    // TrieDB retrieves the low level trie database used for data storage.
    TrieDB() *trie.Database
}

需要使用 TrieDB 这个方法返回的 trie.Database 对象来最终完成 trei 写入 leveldb 的操作,这个方法在 WriteBlockWithState 中会被有条件调用,此处不再深入,谨以此文说明 Block、 StateDB、 Trie 之间的关系

相关文章

网友评论

    本文标题:以太坊 Block 、StateDB 与 Trie 的关系

    本文链接:https://www.haomeiwen.com/subject/dbmhhctx.html