以太坊源码学习笔记

Header.Root 获取 StateDB的流程

2018-05-15  本文已影响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[:])  //从真正数据库获得
}
上一篇下一篇

猜你喜欢

热点阅读