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[:]) //从真正数据库获得
}