區塊鏈教程以太坊源碼分析core-state源碼分析(二)

來源:互聯網
上載者:User

標籤:不清楚   which   its   cannot   []   self   oci   源碼分析   ESS   

## statedb.go

stateDB用來儲存以太坊中關於merkle trie的所有內容。 StateDB負責緩衝和儲存嵌套狀態。 這是檢索合約和賬戶的一般查詢介面:

資料結構

type StateDB struct {    db Database // 後端的資料庫    trie Trie    // trie樹 main account trie    // This map holds ‘live‘ objects, which will get modified while processing a state transition.    // 下面的Map用來儲存當前活動的對象,這些對象在狀態轉換的時候會被修改。    // stateObjects 用來緩衝對象    // stateObjectsDirty用來緩衝被修改過的對象。    stateObjects map[common.Address]*stateObject    stateObjectsDirty map[common.Address]struct{}    // DB error.    // State objects are used by the consensus core and VM which are    // unable to deal with database-level errors. Any error that occurs    // during a database read is memoized here and will eventually be returned    // by StateDB.Commit.    dbErr error    // The refund counter, also used by state transitioning.    // refund計數器。 暫時還不清楚功能。    refund *big.Int    thash, bhash common.Hash //當前的transaction hash 和block hash    txIndex int         // 當前的交易的index    logs map[common.Hash][]*types.Log // 日誌 key是交易的hash值    logSize uint    preimages map[common.Hash][]byte // EVM計算的 SHA3->byte[]的映射關係    // Journal of state modifications. This is the backbone of    // Snapshot and RevertToSnapshot.    // 狀態修改日誌。 這是Snapshot和RevertToSnapshot的支柱。    journal journal    validRevisions []revision    nextRevisionId int    lock sync.Mutex}

建構函式

// 一般的用法 statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))

// Create a new state from a given trie
func New(root common.Hash, db Database) (StateDB, error) {
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{}),
refund: new(big.Int),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
}, nil
}

對於Log的處理

state提供了Log的處理,這比較意外,因為Log實際上是儲存在區塊鏈中的,並沒有儲存在state trie中, state提供Log的處理, 使用了基於下面的幾個函數。 奇怪的是暫時沒看到如何刪除logs裡面的資訊,如果不刪除的話,應該會越積累越多。 TODO logs 刪除

Prepare函數,在交易執行開始被執行。

AddLog函數,在交易執行過程中被VM執行。添加日誌。同時把日誌和交易關聯起來,添加部分交易的資訊。

GetLogs函數,交易完成取走。

// Prepare sets the current transaction hash and index and block hash which is
// used when the EVM emits new state logs.
func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) {
self.thash = thash
self.bhash = bhash
self.txIndex = ti
}

func (self StateDB) AddLog(log types.Log) {
self.journal = append(self.journal, addLogChange{txhash: self.thash})

log.TxHash = self.thashlog.BlockHash = self.bhashlog.TxIndex = uint(self.txIndex)log.Index = self.logSizeself.logs[self.thash] = append(self.logs[self.thash], log)self.logSize++

}
func (self StateDB) GetLogs(hash common.Hash) []types.Log {
return self.logs[hash]
}

func (self StateDB) Logs() []types.Log {
var logs []*types.Log
for _, lgs := range self.logs {
logs = append(logs, lgs...)
}
return logs
}

stateObject處理

getStateObject,首先從緩衝裡面擷取,如果沒有就從trie樹裡面擷取,並載入到緩衝。

// Retrieve a state object given my the address. Returns nil if not found.
func (self StateDB) getStateObject(addr common.Address) (stateObject stateObject) {
// Prefer ‘live‘ objects.
if obj := self.stateObjects[addr]; obj != nil {
if obj.deleted {
return nil
}
return obj
}

// Load the object from the database.enc, err := self.trie.TryGet(addr[:])if len(enc) == 0 {    self.setError(err)    return nil}var data Accountif err := rlp.DecodeBytes(enc, &data); err != nil {    log.Error("Failed to decode state object", "addr", addr, "err", err)    return nil}// Insert into the live set.obj := newObject(self, addr, data, self.MarkStateObjectDirty)self.setStateObject(obj)return obj

}

MarkStateObjectDirty, 設定一個stateObject為Dirty。 直接往stateObjectDirty對應的地址插入一個空結構體。

// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *StateDB) MarkStateObjectDirty(addr common.Address) {
self.stateObjectsDirty[addr] = struct{}{}
}

快照和復原功能

Snapshot可以建立一個快照, 然後通過 RevertToSnapshot可以復原到哪個狀態,這個功能是通過journal來做到的。 每一步的修改都會往journal裡面添加一個undo日誌。 如果需要復原只需要執行undo日誌就行了。

// Snapshot returns an identifier for the current revision of the state.
func (self *StateDB) Snapshot() int {
id := self.nextRevisionId
self.nextRevisionId++
self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)})
return id
}

// RevertToSnapshot reverts all state changes made since the given revision.
func (self *StateDB) RevertToSnapshot(revid int) {
// Find the snapshot in the stack of valid snapshots.
idx := sort.Search(len(self.validRevisions), func(i int) bool {
return self.validRevisions[i].id >= revid
})
if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid {
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
}
snapshot := self.validRevisions[idx].journalIndex

// Replay the journal to undo changes.for i := len(self.journal) - 1; i >= snapshot; i-- {    self.journal[i].undo(self)}self.journal = self.journal[:snapshot]// Remove invalidated snapshots from the stack.self.validRevisions = self.validRevisions[:idx]

}

擷取中間狀態的 root hash值

IntermediateRoot 用來計算當前的state trie的root的hash值。這個方法會在交易執行的過程中被調用。會被存入 transaction receipt

Finalise方法會調用update方法把存放在cache層的修改寫入到trie資料庫裡面。 但是這個時候還沒有寫入底層的資料庫。 還沒有調用commit,資料還在記憶體裡面,還沒有落地成檔案。

// Finalise finalises the state by removing the self destructed objects
// and clears the journal as well as the refunds.
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
for addr := range s.stateObjectsDirty {
stateObject := s.stateObjects[addr]
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
s.deleteStateObject(stateObject)
} else {
stateObject.updateRoot(s.db)
s.updateStateObject(stateObject)
}
}
// Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund()
}

// IntermediateRoot computes the current root hash of the state trie.
// It is called in between transactions to get the root hash that
// goes into transaction receipts.
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
s.Finalise(deleteEmptyObjects)
return s.trie.Hash()
}

commit方法

CommitTo用來提交更改。

// CommitTo writes the state to the given database.
func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
defer s.clearJournalAndRefund()

// Commit objects to the trie.for addr, stateObject := range s.stateObjects {    _, isDirty := s.stateObjectsDirty[addr]    switch {    case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):        // If the object has been removed, don‘t bother syncing it        // and just mark it for deletion in the trie.        s.deleteStateObject(stateObject)    case isDirty:        // Write any contract code associated with the state object        if stateObject.code != nil && stateObject.dirtyCode {            if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {                return common.Hash{}, err            }            stateObject.dirtyCode = false        }        // Write any storage changes in the state object to its storage trie.        if err := stateObject.CommitTrie(s.db, dbw); err != nil {            return common.Hash{}, err        }        // Update the object in the main account trie.        s.updateStateObject(stateObject)    }    delete(s.stateObjectsDirty, addr)}// Write trie changes.root, err = s.trie.CommitTo(dbw)log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())return root, err

}

總結

state包提供了使用者和合約的狀態管理的功能。 管理了狀態和合約的各種狀態轉換。 cach

區塊鏈教程以太坊源碼分析core-state源碼分析(二)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.