美文网首页码农的世界深入浅出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