Header.Root 獲取 StateDB的流程

1.數(shù)據(jù)結(jié)構(gòu)

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  //一級(jí)緩存
}

go-ethereum/trie/database.go

type Database struct {  //trie.Database
    diskdb ethdb.Database // Persistent storage for matured trie nodes //真實(shí)db
    //二級(jí)緩存
    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

//從一級(jí)緩存cachingDB的pastTries獲取SecureTrie
//如果沒有, 則創(chuàng)建
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()
    //是否已經(jīng)存在
    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)  //構(gòu)造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

從二級(jí)緩存nodes獲取, 如果沒有就從數(shù)據(jù)庫讀取
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[:])  //從真正數(shù)據(jù)庫獲得
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容