美文网首页以太坊源码学习笔记
Header.Root 获取 StateDB的流程

Header.Root 获取 StateDB的流程

作者: 坠叶飘香 | 来源:发表于2018-05-15 09:58 被阅读0次

    1.数据结构

    go-ethereum/core/blockchain.go

    type BlockChain struct {
        //cachingDB
        stateCache   state.Database // State database to reuse between imports (contains state cache) 
    }
    

    go-ethereum/core/state/database.go

    type cachingDB struct {
        db            *trie.Database
        pastTries     []*trie.SecureTrie  //一级缓存
    }
    

    go-ethereum/trie/database.go

    type Database struct {  //trie.Database
        diskdb ethdb.Database // Persistent storage for matured trie nodes //真实db
        //二级缓存
        nodes     map[common.Hash]*cachedNode // Data and references relationships of a node 
    }
    

    go-ethereum/trie/trie.go

    type Trie struct {
        db           *Database  //trie.Database
        root         node  //缓存是db的nodes
        originalRoot common.Hash
    }
    

    go-ethereum/core/state/database.go

    // cachedTrie inserts its trie into a cachingDB on commit.
    type cachedTrie struct {
        *trie.SecureTrie
        db *cachingDB
    }
    

    go-ethereum/trie/secure_trie.go

    type SecureTrie struct {
        trie             Trie
        hashKeyBuf       [common.HashLength]byte
        secKeyCache      map[string][]byte
        secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch
    }
    

    2. 代码流程

    go-ethereum/core/state/statedb.go

    2.1. New
    func New(root common.Hash, db Database) (*StateDB, error) { //db: BlockChain.stateCache
        tr, err := db.OpenTrie(root)
        if err != nil {
            return nil, err
        }
        return &StateDB{
            db:                db,
            trie:              tr,
            stateObjects:      make(map[common.Address]*stateObject),
            stateObjectsDirty: make(map[common.Address]struct{}),
            logs:              make(map[common.Hash][]*types.Log),
            preimages:         make(map[common.Hash][]byte),
            journal:           newJournal(),
        }, nil
    }
    
    2.2. OpenTrie

    //从一级缓存cachingDB的pastTries获取SecureTrie
    //如果没有, 则创建
    go-ethereum/core/state/database.go

    // OpenTrie opens the main account trie.
    func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { //返回值是 cachedTrie类型
        db.mu.Lock()
        defer db.mu.Unlock()
        //是否已经存在
        for i := len(db.pastTries) - 1; i >= 0; i-- {   //[]*trie.SecureTrie
            if db.pastTries[i].Hash() == root {
                return cachedTrie{db.pastTries[i].Copy(), db}, nil
            }
        }
        tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen) //不存在,则需要新建
        if err != nil {
            return nil, err
        }
        return cachedTrie{tr, db}, nil    //SecureTrie -> cachedTrie
    }
    
    2.3. NewSecure

    go-ethereum/trie/secure_trie.go

    func NewSecure(root common.Hash, db *Database, cachelimit uint16) (*SecureTrie, error) {
        if db == nil {
            panic("trie.NewSecure called without a database")
        }
        trie, err := New(root, db)  //新建
        if err != nil {
            return nil, err
        }
        trie.SetCacheLimit(cachelimit)
        return &SecureTrie{trie: *trie}, nil    //Trie -> SecureTrie
    }
    
    2.4. New

    go-ethereum/trie/trie.go

    func New(root common.Hash, db *Database) (*Trie, error) {
        if db == nil {
            panic("trie.New called without a database")
        }
        trie := &Trie{
            db:           db,
            originalRoot: root,
        }
        if (root != common.Hash{}) && root != emptyRoot {
            rootnode, err := trie.resolveHash(root[:], nil)  //构造trie.root的值
            if err != nil {
                return nil, err
            }
            trie.root = rootnode
        }
        return trie, nil
    }
    
    2.5. resolveHash

    go-ethereum/trie/trie.go

    func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
        cacheMissCounter.Inc(1)
    
        hash := common.BytesToHash(n)
    
        enc, err := t.db.Node(hash)
        if err != nil || enc == nil {
            return nil, &MissingNodeError{NodeHash: hash, Path: prefix}
        }
        return mustDecodeNode(n, enc, t.cachegen), nil
    }
    
    2.6. Node

    从二级缓存nodes获取, 如果没有就从数据库读取
    go-ethereum/trie/database.go

    // Node retrieves a cached trie node from memory. If it cannot be found cached,
    // the method queries the persistent database for the content.
    func (db *Database) Node(hash common.Hash) ([]byte, error) {
        // Retrieve the node from cache if available
        db.lock.RLock()
        node := db.nodes[hash]
        db.lock.RUnlock()
    
        if node != nil {
            return node.blob, nil
        }
        // Content unavailable in memory, attempt to retrieve from disk
        return db.diskdb.Get(hash[:])  //从真正数据库获得
    }
    

    相关文章

      网友评论

        本文标题:Header.Root 获取 StateDB的流程

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