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

來源:互聯網
上載者:User

標籤:ext   dual   tco   沒有   eval   The   was   div   amp   

區塊鏈教程以太坊源碼分析core-state源碼分析,core/state 包主要為以太坊的state trie提供了一層緩衝層(cache)

database主要提供了trie樹的抽象,提供trie樹的緩衝和合約代碼長度的緩衝。
journal主要提供了動作記錄,以及操作復原的功能。
state_object是account對象的抽象,提供了賬戶的一些功能。
statedb主要是提供了state trie的部分功能。

database.go

database.go 提供了一個資料庫的抽象。

資料結構

// Database wraps access to tries and contract code.type Database interface {    // Accessing tries:    // OpenTrie opens the main account trie.    // OpenStorageTrie opens the storage trie of an account.    // OpenTrie 開啟了主帳號的trie樹    // OpenStorageTrie 開啟了一個帳號的storage trie    OpenTrie(root common.Hash) (Trie, error)    OpenStorageTrie(addrHash, root common.Hash) (Trie, error)    // Accessing contract code:    // 訪問合約代碼    ContractCode(addrHash, codeHash common.Hash) ([]byte, error)    // 訪問合約的大小。 這個方法可能經常被調用。因為有緩衝。    ContractCodeSize(addrHash, codeHash common.Hash) (int, error)    // CopyTrie returns an independent copy of the given trie.    // CopyTrie 返回了一個指定trie的獨立的copy    CopyTrie(Trie) Trie}// NewDatabase creates a backing store for state. The returned database is safe for// concurrent use and retains cached trie nodes in memory.func NewDatabase(db ethdb.Database) Database {    csc, _ := lru.New(codeSizeCacheSize)    return &cachingDB{db: db, codeSizeCache: csc}}type cachingDB struct {    db ethdb.Database    mu sync.Mutex    pastTries []*trie.SecureTrie //trie樹的緩衝    codeSizeCache *lru.Cache         //合約代碼大小的緩衝}

OpenTrie,從緩衝裡面尋找。如果找到了返回緩衝的trie的copy, 否則重新構建一顆樹返回。

func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {    db.mu.Lock()    defer db.mu.Unlock()    for i := len(db.pastTries) - 1; i >= 0; i-- {        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}func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {    return trie.NewSecure(root, db.db, 0)}

ContractCode 和 ContractCodeSize, ContractCodeSize有緩衝。

func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {    code, err := db.db.Get(codeHash[:])    if err == nil {        db.codeSizeCache.Add(codeHash, len(code))    }    return code, err}func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {    if cached, ok := db.codeSizeCache.Get(codeHash); ok {        return cached.(int), nil    }    code, err := db.ContractCode(addrHash, codeHash)    if err == nil {        db.codeSizeCache.Add(codeHash, len(code))    }    return len(code), err}

cachedTrie的結構和commit方法,commit的時候會調用pushTrie方法把之前的Trie樹緩衝起來。

// cachedTrie inserts its trie into a cachingDB on commit.type cachedTrie struct {    *trie.SecureTrie    db *cachingDB}func (m cachedTrie) CommitTo(dbw trie.DatabaseWriter) (common.Hash, error) {    root, err := m.SecureTrie.CommitTo(dbw)    if err == nil {        m.db.pushTrie(m.SecureTrie)    }    return root, err}func (db *cachingDB) pushTrie(t *trie.SecureTrie) {    db.mu.Lock()    defer db.mu.Unlock()    if len(db.pastTries) >= maxPastTries {        copy(db.pastTries, db.pastTries[1:])        db.pastTries[len(db.pastTries)-1] = t    } else {        db.pastTries = append(db.pastTries, t)    }}

journal.go

journal代表了動作記錄, 並針對各種操作的日誌提供了對應的復原功能。 可以基於這個日誌來做一些事務類型的操作。

類型定義,定義了journalEntry這個介面,提供了undo的功能。 journal 就是journalEntry的列表。

type journalEntry interface {    undo(*StateDB)}type journal []journalEntry

各種不同的日誌類型以及undo方法。

createObjectChange struct { //建立對象的日誌。 undo方法就是從StateDB中刪除建立的對象。    account *common.Address}func (ch createObjectChange) undo(s *StateDB) {    delete(s.stateObjects, *ch.account)    delete(s.stateObjectsDirty, *ch.account)}// 對於stateObject的修改, undo方法就是把值改為原來的對象。resetObjectChange struct {    prev *stateObject}func (ch resetObjectChange) undo(s *StateDB) {    s.setStateObject(ch.prev)}// 自殺的更改。自殺應該是刪除帳號,但是如果沒有commit的化,對象還沒有從stateDB刪除。suicideChange struct {    account *common.Address    prev bool // whether account had already suicided    prevbalance *big.Int}func (ch suicideChange) undo(s *StateDB) {    obj := s.getStateObject(*ch.account)    if obj != nil {        obj.suicided = ch.prev        obj.setBalance(ch.prevbalance)    }}// Changes to individual accounts.balanceChange struct {    account *common.Address    prev *big.Int}nonceChange struct {    account *common.Address    prev uint64}storageChange struct {    account *common.Address    key, prevalue common.Hash}codeChange struct {    account *common.Address    prevcode, prevhash []byte}func (ch balanceChange) undo(s *StateDB) {    s.getStateObject(*ch.account).setBalance(ch.prev)}func (ch nonceChange) undo(s *StateDB) {    s.getStateObject(*ch.account).setNonce(ch.prev)}func (ch codeChange) undo(s *StateDB) {    s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)}func (ch storageChange) undo(s *StateDB) {    s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)}// 我理解是DAO事件的退款處理refundChange struct {    prev *big.Int}func (ch refundChange) undo(s *StateDB) {    s.refund = ch.prev}// 增加了日誌的修改addLogChange struct {    txhash common.Hash}func (ch addLogChange) undo(s *StateDB) {    logs := s.logs[ch.txhash]    if len(logs) == 1 {        delete(s.logs, ch.txhash)    } else {        s.logs[ch.txhash] = logs[:len(logs)-1]    }    s.logSize--}// 這個是增加 VM看到的 SHA3的 原始byte[], 增加SHA3 hash -> byte[] 的對應關係addPreimageChange struct {    hash common.Hash}func (ch addPreimageChange) undo(s *StateDB) {    delete(s.preimages, ch.hash)}touchChange struct {    account *common.Address    prev bool    prevDirty bool}var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")func (ch touchChange) undo(s *StateDB) {    if !ch.prev && *ch.account != ripemd {        s.getStateObject(*ch.account).touched = ch.prev        if !ch.prevDirty {            delete(s.stateObjectsDirty, *ch.account)        }    }}

state_object.go

stateObject表示正在修改的以太坊帳戶。

資料結構

type Storage map[common.Hash]common.Hash// stateObject represents an Ethereum account which is being modified.// stateObject表示正在修改的以太坊帳戶。// The usage pattern is as follows:// First you need to obtain a state object.// Account values can be accessed and modified through the object.// Finally, call CommitTrie to write the modified storage trie into a database.使用模式如下:首先你需要獲得一個state_object。帳戶值可以通過對象訪問和修改。最後,調用CommitTrie將修改後的儲存trie寫入資料庫。type stateObject struct {    address common.Address    addrHash common.Hash // hash of ethereum address of the account 以太坊帳號地址的hash值    data Account // 這個是實際的以太坊帳號的資訊    db *StateDB //狀態資料庫    // 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.    //    資料庫錯誤。    stateObject會被共識演算法的核心和VM使用,在這些代碼內部無法處理資料庫層級的錯誤。    在資料庫讀取期間發生的任何錯誤都會在這裡被儲存,最終將由StateDB.Commit返回。    dbErr error    // Write caches. 寫緩衝    trie Trie // storage trie, which becomes non-nil on first access 使用者的儲存trie ,在第一次訪問的時候變得非空    code Code // contract bytecode, which gets set when code is loaded 合約代碼,當代碼被載入的時候被設定    cachedStorage Storage // Storage entry cache to avoid duplicate reads 使用者儲存物件的緩衝,用來避免重複讀    dirtyStorage Storage // Storage entries that need to be flushed to disk 需要刷入磁碟的使用者儲存物件    // Cache flags. Cache 標誌    // When an object is marked suicided it will be delete from the trie    // during the "update" phase of the state transition.    // 當一個對象被標記為自殺時,它將在狀態轉換的“更新”階段期間從樹中刪除。    dirtyCode bool // true if the code was updated 如果代碼被更新,會設定為true    suicided bool    touched bool    deleted bool    onDirty func(addr common.Address) // Callback method to mark a state object newly dirty 第一次被設定為drity的時候會被調用。}// Account is the Ethereum consensus representation of accounts.// These objects are stored in the main account trie.// 帳戶是以太坊共識表示的帳戶。 這些Object Storage Service在main account trie。type Account struct {    Nonce uint64    Balance *big.Int    Root common.Hash // merkle root of the storage trie    CodeHash []byte}

建構函式

// newObject creates a state object.func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject {    if data.Balance == nil {        data.Balance = new(big.Int)    }    if data.CodeHash == nil {        data.CodeHash = emptyCodeHash    }    return &stateObject{        db: db,        address: address,        addrHash: crypto.Keccak256Hash(address[:]),        data: data,        cachedStorage: make(Storage),        dirtyStorage: make(Storage),        onDirty: onDirty,    }}

RLP的編碼方式,只會編碼 Account對象。

// EncodeRLP implements rlp.Encoder.func (c *stateObject) EncodeRLP(w io.Writer) error {    return rlp.Encode(w, c.data)}

一些狀態改變的函數。

func (self *stateObject) markSuicided() {    self.suicided = true    if self.onDirty != nil {        self.onDirty(self.Address())        self.onDirty = nil    }}func (c *stateObject) touch() {    c.db.journal = append(c.db.journal, touchChange{        account: &c.address,        prev: c.touched,        prevDirty: c.onDirty == nil,    })    if c.onDirty != nil {        c.onDirty(c.Address())        c.onDirty = nil    }    c.touched = true}

Storage的處理

// getTrie返回賬戶的Storage Triefunc (c *stateObject) getTrie(db Database) Trie {    if c.trie == nil {        var err error        c.trie, err = db.OpenStorageTrie(c.addrHash, c.data.Root)        if err != nil {            c.trie, _ = db.OpenStorageTrie(c.addrHash, common.Hash{})            c.setError(fmt.Errorf("can‘t create storage trie: %v", err))        }    }    return c.trie}// GetState returns a value in account storage.// GetState 返回account storage 的一個值,這個值的類型是Hash類型。// 說明account storage裡面只能儲存hash值?// 如果緩衝裡面存在就從緩衝裡尋找,否則從資料庫裡面查詢。然後儲存到緩衝裡面。func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {    value, exists := self.cachedStorage[key]    if exists {        return value    }    // Load from DB in case it is missing.    enc, err := self.getTrie(db).TryGet(key[:])    if err != nil {        self.setError(err)        return common.Hash{}    }    if len(enc) > 0 {        _, content, _, err := rlp.Split(enc)        if err != nil {            self.setError(err)        }        value.SetBytes(content)    }    if (value != common.Hash{}) {        self.cachedStorage[key] = value    }    return value}// SetState updates a value in account storage.// 往 account storeage 裡面設定一個值 key value 的類型都是Hash類型。func (self *stateObject) SetState(db Database, key, value common.Hash) {    self.db.journal = append(self.db.journal, storageChange{        account: &self.address,        key: key,        prevalue: self.GetState(db, key),    })    self.setState(key, value)}func (self *stateObject) setState(key, value common.Hash) {    self.cachedStorage[key] = value    self.dirtyStorage[key] = value    if self.onDirty != nil {        self.onDirty(self.Address())        self.onDirty = nil    }}

提交 Commit

// CommitTrie the storage trie of the object to dwb.// This updates the trie root.// 步驟,首先開啟,然後修改,然後提交或者復原func (self *stateObject) CommitTrie(db Database, dbw trie.DatabaseWriter) error {    self.updateTrie(db) // updateTrie把修改過的緩衝寫入Trie樹    if self.dbErr != nil {        return self.dbErr    }    root, err := self.trie.CommitTo(dbw)    if err == nil {        self.data.Root = root    }    return err}// updateTrie writes cached storage modifications into the object‘s storage trie.func (self *stateObject) updateTrie(db Database) Trie {    tr := self.getTrie(db)    for key, value := range self.dirtyStorage {        delete(self.dirtyStorage, key)        if (value == common.Hash{}) {            self.setError(tr.TryDelete(key[:]))            continue        }        // Encoding []byte cannot fail, ok to ignore the error.        v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))        self.setError(tr.TryUpdate(key[:], v))    }    return tr}// UpdateRoot sets the trie root to the current root hash of// 把帳號的root設定為當前的trie樹的跟。func (self *stateObject) updateRoot(db Database) {    self.updateTrie(db)    self.data.Root = self.trie.Hash()}

額外的一些功能 ,deepCopy提供了state_object的深拷貝。

func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {    stateObject := newObject(db, self.address, self.data, onDirty)    if self.trie != nil {        stateObject.trie = db.db.CopyTrie(self.trie)    }    stateObject.code = self.code    stateObject.dirtyStorage = self.dirtyStorage.Copy()    stateObject.cachedStorage = self.dirtyStorage.Copy()    stateObject.suicided = self.suicided    stateObject.dirtyCode = self.dirtyCode    stateObject.deleted = self.deleted    return stateObject}

未完待續…感謝繼續關注兄弟連區塊鏈教程分享

區塊鏈教程以太坊源碼分析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.