2018-01-28整理

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

// block塊數(shù)據(jù)
    type Block struct {
        header       *Header
        uncles       []*Header
        transactions Transactions

        // caches
        hash atomic.Value
        size atomic.Value

        // Td is used by package core to store the total difficulty
        // of the chain up to and including the block.
        td *big.Int

        // These fields are used by package eth to track
        // inter-peer block relay.
        ReceivedAt   time.Time
        ReceivedFrom interface{}
    }
    
// header數(shù)據(jù)
    type Header struct {
        ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"` // 指向父區(qū)塊的指針踱蛀。
        UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"` // Block結(jié)構(gòu)體的成員uncles的RLP哈希值。
        Coinbase    common.Address `json:"miner"            gencodec:"required"` // 挖掘出這個(gè)區(qū)塊的作者地址。
        Root        common.Hash    `json:"stateRoot"        gencodec:"required"` // StateDB中的“state Trie”的根節(jié)點(diǎn)的RLP哈希值。
        TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"` // Block中 “tx Trie”的根節(jié)點(diǎn)的RLP哈希值盔憨。
        ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"` // Block中的 "Receipt Trie”的根節(jié)點(diǎn)的RLP哈希值浙宜。
        Bloom       Bloom          `json:"logsBloom"        gencodec:"required"` // Bloom過濾器(Filter)平夜,用來快速判斷一個(gè)參數(shù)Log對(duì)象是否存在于一組已知的Log集合中线脚。
        Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"` // 區(qū)塊的難度。
        Number      *big.Int       `json:"number"           gencodec:"required"` // 區(qū)塊的序號(hào)板甘。
        GasLimit    uint64         `json:"gasLimit"         gencodec:"required"` // 區(qū)塊內(nèi)所有Gas消耗的理論上限党瓮。
        GasUsed     uint64         `json:"gasUsed"          gencodec:"required"` // 區(qū)塊內(nèi)所有Transaction執(zhí)行時(shí)所實(shí)際消耗的Gas總和。
        Time        *big.Int       `json:"timestamp"        gencodec:"required"` // 區(qū)塊時(shí)間戳盐类,要么等于parentBlock.Time + 10s寞奸,要么等于當(dāng)前系統(tǒng)時(shí)間。
        Extra       []byte         `json:"extraData"        gencodec:"required"` // ?
        MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"` // ?
        Nonce       BlockNonce     `json:"nonce"            gencodec:"required"` // 挖礦隨機(jī)數(shù)在跳,一個(gè)64bit的哈希數(shù)蝇闭。
    }
    
// Transaction數(shù)據(jù)
    type Transaction struct {
        data txdata  //交易明細(xì)
        // caches
        hash atomic.Value // 交易hash
        size atomic.Value // ?
        from atomic.Value // from地址
    }
    type txdata struct {
        AccountNonce uint64          `json:"nonce"    gencodec:"required"`
        Price        *big.Int        `json:"gasPrice" gencodec:"required"`
        GasLimit     uint64          `json:"gas"      gencodec:"required"`
        Recipient    *common.Address `json:"to"       rlp:"nil"` // nil means contract creation
        Amount       *big.Int        `json:"value"    gencodec:"required"`
        Payload      []byte          `json:"input"    gencodec:"required"`

        // Signature values
        V *big.Int `json:"v" gencodec:"required"`
        R *big.Int `json:"r" gencodec:"required"`
        S *big.Int `json:"s" gencodec:"required"`

        // This is only used when marshaling to JSON.
        Hash *common.Hash `json:"hash" rlp:"-"`
    }

// 塊數(shù)據(jù)示例
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "difficulty": "0x7b56814e8e0",
        "extraData": "0xd783010203844765746887676f312e342e32856c696e7578",
        "gasLimit": "0x2fefd8",
        "gasUsed": "0x37c5e",
        "hash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
        "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000400000000000000000000040000000000000",
        "miner": "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5",
        "mixHash": "0x40384589c970bff24a4d5d87692cfd948c89cb7e5381ad28d31071e85c7f22b6",
        "nonce": "0xda9cbaa29db514a5",
        "number": "0xaae61",
        "parentHash": "0x6c621dc6d89cecd48004bd6bd6f3098a18f61aa140b912f0db583198cb69558e",
        "receiptsRoot": "0x852ede9b7d114119ecf6f6221f9f6ed059bb25e098ffc6ae89f451186d44c056",
        "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
        "size": "0x572",
        "stateRoot": "0x3b65505100e6fdfa2649764e63a7a980aebfd93726690fe0239e384ede4e3980",
        "timestamp": "0x567137a7",
        "totalDifficulty": "0x3b49b0afd6d0597c",
        "transactionsRoot": "0xb42c31f189406cc77674b5e6f7a7b7d63dd895f875befb3351fb117f37580d38",
        "uncles": [],
        "transactions": [
            {
                "blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
                "blockNumber": "0xaae61",
                "from": "0xcba4c3cc041b09d3cbf416b73633cb6bd21c88f8",
                "gas": "0x3d090",
                "gasPrice": "0xc1b710800",
                "hash": "0x8c1dd51958fc97a95a24acce4cafba517337138545b57a84cdef3e970bbdf919",
                "input": "0x651e723c000000000000000000000000f0b019bb52f59680845b670453ffd875ae3a59e400000000000000000000000000000000000000000000000000000000567137b900000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002961caac0fcae0a7f51e4131ef6a243df537d11696bb1a27bac34e37a7c198b9b7ca5c71e62ed55fbca1516ad12305849bfb7421cc199d40dd08f8bb8bd0b57dc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000f0b019bb52f59680845b670453ffd875ae3a59e400000000000000000000000059cc8539f5515335f1340662ce569fa988b40938000000000000000000000000761566074a8e0f7063044abfb8c80ca4cd8c5fd3000000000000000000000000d4fcbd984baebcc12f70f9a151c5c5708d825a7f",
                "nonce": "0x35",
                "to": "0x7de5aba7de728950c92c57d08e20d4077161f12f",
                "transactionIndex": "0x0",
                "value": "0x1",
                "v": "0x1b",
                "r": "0x378066c58af812dc57dc3d090cd6717338d1e51bc1d6fbc308e293ebb69089b",
                "s": "0x6208bfb9f67145ce1ac7fadb65682f3a2ea43380e80d07f6d0eab8e5fc5df926"
            },
            {
                "blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
                "blockNumber": "0xaae61",
                "from": "0xf8b483dba2c3b7176a3da549ad41a48bb3121069",
                "gas": "0x15f90",
                "gasPrice": "0xba43b7400",
                "hash": "0x5408d12bde03366c4a4b9ad484341bd1c69f86c58ef27a792d1fff1ceda6a6be",
                "input": "0x",
                "nonce": "0x7e55",
                "to": "0xec33b995e319527958760affd24f61fee029e4f9",
                "transactionIndex": "0x1",
                "value": "0x15c98d913a1bc00",
                "v": "0x1c",
                "r": "0xd308fb2c73d6f72545d0f7f5b9ac393f28834bb1f4c64c625cfb71f6ff0fd9f4",
                "s": "0x20ca14e9481c8c8a97ed2d761f3692e05fb3d7dc262176203670be6d6f934573"
            },
            {
                "blockHash": "0x3d3ebb11286a91fdc00cfb6ffa4f4a73e3e528ce13467bb2203532dc9cb42a8f",
                "blockNumber": "0xaae61",
                "from": "0x2a65aca4d5fc5b5c859090a6c34d164135398226",
                "gas": "0x15f90",
                "gasPrice": "0xba43b7400",
                "hash": "0x5d8cb5dfd613171daf733f65baefe727060bef89e705a4a7ac46cda1ffb53744",
                "input": "0x",
                "nonce": "0xf4ae",
                "to": "0x7fdf07a0f977e4032c1f082df831423abf58d13d",
                "transactionIndex": "0x2",
                "value": "0xf6ceba93384a000",
                "v": "0x1b",
                "r": "0xa24aefa55e9e47915a0b67bbac1b4cc0a823574077cb60a0b2f75f05eec758e8",
                "s": "0x1b2b89d5a963003283b81c5da14e58b52a611827db1066f0992d36b2fd88a4d"
            }
        ]
    }
} 

database_util.go 說明

    // 初始化前綴信息
    headHeaderKey = []byte("LastHeader")  // 最新區(qū)塊頭 Headchain中使用
    headBlockKey  = []byte("LastBlock")   // 最新區(qū)塊   BlockChain中使用
    headFastKey   = []byte("LastFast")   //  最新快速同步的區(qū)塊頭 這里“LastFast”所存儲(chǔ)的是在一種特別的同步方式FastSync下,最新Block的canonical hash硬毕。FastSync相比于FullSync,可以僅僅同步Header而不考慮Body礼仗,故此得名Fast吐咳。

    // Data item prefixes (use single byte to avoid mixing data types, avoid `i`). ETH定義好的區(qū)塊頭前綴標(biāo)識(shí),key的前綴可以區(qū)分leveldb中存儲(chǔ)的是什么類型的數(shù)據(jù)。
    headerPrefix        = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header   區(qū)塊頭key前綴
    tdSuffix            = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td  區(qū)塊難度
    numSuffix           = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash  區(qū)塊高度
    blockHashPrefix     = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian) 區(qū)塊hash前綴
    bodyPrefix          = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body 區(qū)塊體前綴
    blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts 區(qū)塊交易收據(jù)
    lookupPrefix        = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata
    bloomBitsPrefix     = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits

    preimagePrefix = "secure-key-"              // preimagePrefix + hash -> preimage
    configPrefix   = []byte("ethereum-config-") // config prefix for the db

    // Chain index prefixes (use `i` + single byte to avoid mixing data types).
    BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress

    // used by old db, now only used for conversion
    oldReceiptsPrefix = []byte("receipts-")
    oldTxMetaSuffix   = []byte{0x01}

    ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error

    preimageCounter    = metrics.NewCounter("db/preimage/total")
    preimageHitCounter = metrics.NewCounter("db/preimage/hits")
  • 方法歸類整理
 數(shù)據(jù)庫操作封裝
1.塊hash -> 塊頭
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header

a.WriteHeader()
b.GetHeaderRLP() 
c.GetHeader() 
d.DeleteHeader()


2.塊hash -> 總難度
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td

a.WriteTd()
b.GetTd()
c.DeleteTd()


3.塊高 -> 塊hash
numSuffix  = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash  

canonical hash:區(qū)塊hash元践,Block(或Header)對(duì)象的RLP哈希值韭脊。
num(Number)和hash是Block最為重要的兩個(gè)屬性:num用來確定Block在整個(gè)區(qū)塊鏈中所處的位置,hash用來辨識(shí)惟一的Block/Header對(duì)象单旁。

a.encodeBlockNumber(number uint64) //將區(qū)塊高度轉(zhuǎn)化為ig endian uint64類型,大端格式
b.GetCanonicalHash()  
c.WriteCanonicalHash() 
d.DeleteCanonicalHash()


4.塊hash -> 塊高
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)


5.塊hash -> body數(shù)據(jù)
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body

a.WriteBodyRLP()
b.GetBodyRLP()
c.WriteBody()
d.GetBody() 
e.DeleteBody()


6.塊hash -> 交易收據(jù)
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts

a.WriteBlockReceipts()
b.GetBlockReceipts()
c.DeleteBlockReceipts()


7.塊hash -> 交易收據(jù)lookup metadata
lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata

a.WriteTxLookupEntries()
b.GetTxLookupEntry()
c.DeleteTxLookupEntry()


8.塊高 -> bloom bits
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit(uint16 big endian) + section(uint64 big endian) + hash -> bloom bits

a.WriteBloomBits() 
b.GetBloomBits()


9.沒看懂
preimagePrefix = "secure-key-"  // preimagePrefix + hash -> preimage(原像)

WritePreimages()


10.eth配置數(shù)據(jù)庫信息
configPrefix = []byte("ethereum-config-") // config prefix for the db

a.WriteChainConfig()
b.GetChainConfig()


11.沒看懂
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress 索引進(jìn)度跟蹤


12.//used by old db, now only used for conversion 轉(zhuǎn)換
oldReceiptsPrefix = []byte("receipts-")
oldTxMetaSuffix   = []byte{0x01}


對(duì)外封裝方法:
1.初始化數(shù)據(jù)
  missingNumber  // 如果數(shù)據(jù)庫中沒有獲取到塊高數(shù)據(jù)沪羔,則使用該缺省塊高。
  TxLookupEntry  //Lookup實(shí)體

2.塊高
  GetBlockNumber()  //返回missingNumber/塊高
  
3.塊hash
  WriteHeadHeaderHash() 
  GetHeadHeaderHash() //返回當(dāng)前塊頭的hash

  WriteHeadBlockHash()
  GetHeadBlockHash() //返回當(dāng)前塊頭的hash

  WriteHeadFastBlockHash()
  GetHeadFastBlockHash() //返回當(dāng)前塊頭的hash

4.區(qū)塊操作
  WriteBlock()
  GetBlock()
  DeleteBlock()

5.區(qū)塊頭操作
  FindCommonAncestor() // 獲取兩個(gè)區(qū)塊頭的共同父類區(qū)塊頭信息?
  
6.交易信息
  GetTransaction()
  
7.交易收據(jù)信息
  GetReceipt()
  
8.區(qū)塊鏈操作
  WriteBlockChainVersion()
  GetBlockChainVersion()

9.公用方法
  headerKey()  //公用headerKey生成
  blockBodyKey() //公用bodyKey生成

數(shù)據(jù)庫體系

image

LDBDatabase

屬于Ethereum代碼范圍內(nèi)的最底層數(shù)據(jù)庫是ethdb.LDBDatabase,它通過持有一個(gè)levelDB的對(duì)象蔫饰,最終為Ethereum世界里所有需要存儲(chǔ)/讀取[k,b]的需求提供服務(wù)琅豆。

ethDB.png
  • interface.go
    統(tǒng)一接口封裝,包含數(shù)據(jù)庫的單/批操作方法(putter,get,has,delete,close,batch)
  • database.go
    a.NewLDBDatabase()--初始化LevelDB實(shí)例,初始化數(shù)據(jù)庫數(shù)據(jù)篓吁,文件緩存容量+塊緩存容量+寫緩存等
    b.Put()--保存數(shù)據(jù)茫因,將數(shù)據(jù)放入levelDB存儲(chǔ)隊(duì)列
    c.Has()--校驗(yàn)key值在LevelDB中是否存在
    d.Get()--查詢key對(duì)應(yīng)的value值
    e.Delete()--刪除key對(duì)應(yīng)的數(shù)據(jù)
    f.NewIterator()--創(chuàng)建LevelDB數(shù)據(jù)遍歷器
    g.Close()--數(shù)據(jù)庫關(guān)閉操作
    h.Meter()--初始化特殊請(qǐng)求前綴,并啟動(dòng)監(jiān)聽程序
    i.NewBatch()--初始化批處理實(shí)例杖剪,后續(xù)提供了相關(guān)Put/ValueSize/Write等方法
    j.table/tableBatch--按照前綴操作單/批量數(shù)據(jù)的實(shí)例冻押,后續(xù)提供了相關(guān)Put/Has/Get/Delete/Close等方法
  • database_test.go
    基于database.go對(duì)外提供的測(cè)試接口
  • memory_database.go
    使用內(nèi)存變量模擬數(shù)據(jù)庫單/批的并行操作

Trie

圖中多次出現(xiàn)一種類似的設(shè)計(jì)模式,比如trie.Trie持有一個(gè)本地接口trie.<<Database>>盛嘿,而后者的具體實(shí)現(xiàn)是ethdb.LDBDatabase洛巢。這種設(shè)計(jì)模式其實(shí)是golang的語法帶來的。在golang中次兆,一個(gè)結(jié)構(gòu)體(類)要實(shí)現(xiàn)另一個(gè)接口的所有方法稿茉,不必在結(jié)構(gòu)體聲明時(shí)顯式繼承那個(gè)接口,只要完全實(shí)現(xiàn)那些方法类垦。這樣狈邑,當(dāng)一個(gè)結(jié)構(gòu)體想調(diào)用另一個(gè)包路徑下結(jié)構(gòu)體的多個(gè)方法時(shí),可以聲明一個(gè)本地接口蚤认,帶有幾個(gè)同想要調(diào)用方法完全一樣的方法米苹,就可以了,這種方式的優(yōu)點(diǎn)是不同包之間的代碼更充分的解耦合砰琢。所以在上圖中蘸嘶,這些輔助性的本地接口全都被標(biāo)為灰色,只需要關(guān)注實(shí)際調(diào)用的實(shí)現(xiàn)類就好了陪汽。

  • 源碼整理
    a.Trie-LevelDB
      實(shí)例:
           Database:DatabaseReader/DatabaseWriter
      方法: 
           DatabaseReader:Get/Has
           DatabaseWriter:Put
           
    b.Trie     
       實(shí)例:
          Trie
            -- root node  始終作為整個(gè)MPT的根節(jié)點(diǎn)
            -- db Database  Trie-LevelDB中數(shù)據(jù)庫操作實(shí)例
            -- originalRoot common.Hash 創(chuàng)建Trie對(duì)象時(shí)承接入?yún)ashNode
            -- cachegen, cachelimit uint16    cacheGen是cache次數(shù)的計(jì)數(shù)器训唱,每次Trie的變動(dòng)提交后(寫入的對(duì)象可由外部參數(shù)傳入),cacheGen自增1
       方法: 
            New  根據(jù)數(shù)據(jù)庫數(shù)據(jù)創(chuàng)建根節(jié)點(diǎn)數(shù)據(jù)挚冤,
            NodeIterator  創(chuàng)建節(jié)點(diǎn)迭代器
            Get  根據(jù)key值返回Trie中的value况增,不報(bào)錯(cuò)
            TryGet   根據(jù)key值返回Trie中的value,報(bào)錯(cuò)(MissingNodeError)
            Update/TryUpdate   根據(jù)key更新(insert)value训挡,如果value長度為0澳骤,則從Trie中刪除并返回nil。
            Delete/TryDelete
            Commit/CommitTo    將trie記錄提交至數(shù)據(jù)庫

State

系統(tǒng)設(shè)計(jì)中澜薄,在底層數(shù)據(jù)庫模塊和業(yè)務(wù)模型之間为肮,往往需要設(shè)置本地存儲(chǔ)模塊,它面向業(yè)務(wù)模型肤京,可以根據(jù)業(yè)務(wù)需求靈活的設(shè)計(jì)各種存儲(chǔ)格式和單元颊艳,同時(shí)又連接底層數(shù)據(jù)庫,如果底層數(shù)據(jù)庫(或者第三方API)有變動(dòng),可以大大減少對(duì)業(yè)務(wù)模塊的影響棋枕。在Ethereum世界里白修,StateDB就擔(dān)任這個(gè)角色,它通過大量的stateObject對(duì)象集合戒悠,管理所有“賬戶”信息熬荆。

面向業(yè)務(wù)的存儲(chǔ)模塊 - StateDB

StateDB有一個(gè)trie.Trie類型成員trie,它又被稱為storage trie或stte trie绸狐,這個(gè)MPT結(jié)構(gòu)中存儲(chǔ)的都是stateObject對(duì)象卤恳,每個(gè)stateObject對(duì)象以其地址(20 bytes)作為插入節(jié)點(diǎn)的Key;每次在一個(gè)區(qū)塊的交易開始執(zhí)行前寒矿,trie由一個(gè)哈希值(hashNode)恢復(fù)出來突琳。另外還有一個(gè)map結(jié)構(gòu),也是存放stateObject符相,每個(gè)stateObject的地址作為map的key拆融。那么問題來了,這些數(shù)據(jù)結(jié)構(gòu)之間是怎樣的關(guān)系呢啊终?

image

如上圖所示镜豹,每當(dāng)一個(gè)stateObject有改動(dòng),亦即“賬戶”信息有變動(dòng)時(shí)蓝牲,這個(gè)stateObject對(duì)象會(huì)更新趟脂,并且這個(gè)stateObject會(huì)標(biāo)為dirty,此時(shí)所有的數(shù)據(jù)改動(dòng)還僅僅存儲(chǔ)在map里例衍。當(dāng)IntermediateRoot()調(diào)用時(shí)昔期,所有標(biāo)為dirty的stateObject才會(huì)被一起寫入trie。而整個(gè)trie中的內(nèi)容只有在CommitTo()調(diào)用時(shí)被一起提交到底層數(shù)據(jù)庫佛玄∨鹨唬可見,這個(gè)map被用作本地的一級(jí)緩存梦抢,trie是二級(jí)緩存般贼,底層數(shù)據(jù)庫是第三級(jí),各級(jí)數(shù)據(jù)結(jié)構(gòu)的界限非常清晰奥吩,這樣逐級(jí)緩存數(shù)據(jù)具伍,每一級(jí)數(shù)據(jù)向上一級(jí)提交的時(shí)機(jī)也根據(jù)業(yè)務(wù)需求做了合理的選擇。

StateDB中賬戶狀態(tài)的版本管理

StateDB還可以管理賬戶狀態(tài)的版本圈驼。這個(gè)功能用到了幾個(gè)結(jié)構(gòu)體:journal,revision望几,先來看看UML關(guān)系圖:

image

其中journal對(duì)象是journalEntry的散列绩脆,長度不固定,可任意添加元素。接口journalEntry存在若干種實(shí)現(xiàn)體靴迫,描述了從單個(gè)賬戶操作(賬戶余額惕味,發(fā)起合約次數(shù)等),到account trie變化(創(chuàng)建新賬戶對(duì)象玉锌,賬戶消亡)等各種最小事件名挥。revision結(jié)構(gòu)體,用來描述一個(gè)‘版本’主守,它的兩個(gè)整型成員jd和journalIndex禀倔,都是基于journal散列進(jìn)行操作的。

image

上圖簡述了StateDB中賬戶狀態(tài)的版本是如何管理的参淫。首先journal散列會(huì)隨著系統(tǒng)運(yùn)行不斷的增長啤贩,記錄所有發(fā)生過的單位事件弛车;當(dāng)某個(gè)時(shí)刻需要產(chǎn)生一個(gè)賬戶狀態(tài)版本時(shí),代碼中相應(yīng)的是Snapshop()調(diào)用,會(huì)產(chǎn)生一個(gè)新revision對(duì)象培廓,記錄下當(dāng)前journal散列的長度,和一個(gè)自增1的版本號(hào)越妈。

基于以上的設(shè)計(jì)泪勒,當(dāng)發(fā)生回退要求時(shí),只要根據(jù)相應(yīng)的revision中的journalIndex棕兼,在journal散列上陡舅,根據(jù)所記錄的所有journalEntry,即可使所有賬戶回退到那個(gè)狀態(tài)程储。

Ethereum里的賬戶 - stateObject

每個(gè)stateObject對(duì)象管理著Ethereum世界里的一個(gè)“賬戶”蹭沛。stateObject有一個(gè)成員變量data,類型是Accunt結(jié)構(gòu)體章鲤,里面存有賬戶Ether余額摊灭,合約發(fā)起次數(shù),最新發(fā)起合約指令集的哈希值败徊,以及一個(gè)MPT結(jié)構(gòu)的頂點(diǎn)哈希值帚呼。

stateObject內(nèi)部也有一個(gè)Trie類型的成員trie,被稱為storage trie皱蹦,它里面存放的是一種被稱為State的數(shù)據(jù)煤杀。State跟每個(gè)賬戶相關(guān),格式是[Hash, Hash]鍵值對(duì)沪哺。有意思的是沈自,stateObject內(nèi)部也有類似StateDB一樣的二級(jí)數(shù)據(jù)緩存機(jī)制,用來緩存和更新這些State辜妓。

image

stateObject定義了一種類型名為storage的map結(jié)構(gòu)枯途,用來存放[]Hash,Hash]類型的數(shù)據(jù)對(duì)忌怎,也就是State數(shù)據(jù)。當(dāng)SetState()調(diào)用發(fā)生時(shí)酪夷,storage內(nèi)部State數(shù)據(jù)被更新榴啸,相應(yīng)標(biāo)示為"dirty"。之后晚岭,待有需要時(shí)(比如updateRoot()調(diào)用)鸥印,那些標(biāo)為"dirty"的State數(shù)據(jù)被一起寫入storage trie,而storage trie中的所有內(nèi)容在CommitTo()調(diào)用時(shí)再一起提交到底層數(shù)據(jù)庫坦报。

cachingDB

看代碼封裝了一些對(duì)合約進(jìn)行操作的方法库说,如ContractCode/ContractCodeSize,具體需要后續(xù)研究燎竖。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末璃弄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子构回,更是在濱河造成了極大的恐慌夏块,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纤掸,死亡現(xiàn)場(chǎng)離奇詭異脐供,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)借跪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門政己,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掏愁,你說我怎么就攤上這事歇由。” “怎么了果港?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵沦泌,是天一觀的道長。 經(jīng)常有香客問我辛掠,道長谢谦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任萝衩,我火速辦了婚禮回挽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猩谊。我一直安慰自己千劈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布牌捷。 她就那樣靜靜地躺著墙牌,像睡著了一般袁梗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上憔古,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音淋袖,去河邊找鬼鸿市。 笑死,一個(gè)胖子當(dāng)著我的面吹牛即碗,可吹牛的內(nèi)容都是我干的焰情。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼剥懒,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼内舟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起初橘,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤验游,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后保檐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耕蝉,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年夜只,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了垒在。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扔亥,死狀恐怖场躯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旅挤,我是刑警寧澤踢关,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站谦铃,受9級(jí)特大地震影響耘成,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驹闰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一瘪菌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嘹朗,春花似錦师妙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怔檩。三九已至,卻和暖如春蓄诽,著一層夾襖步出監(jiān)牢的瞬間薛训,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工仑氛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乙埃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓锯岖,卻偏偏與公主長得像介袜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子出吹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 簡介 不管你們知不知道以太坊(Ethereum blockchain)是什么遇伞,但是你們大概都聽說過以太坊。最近在新...
    Lilymoana閱讀 3,889評(píng)論 1 22
  • 譯者序 本文最初是我應(yīng)以太坊中文社區(qū)(Ethfans.org)之邀做的翻譯稿捶牢,原文取自以太坊社區(qū)的 shardin...
    風(fēng)靜縠紋平閱讀 6,536評(píng)論 0 6
  • 前言 《最小可行性區(qū)塊鏈設(shè)計(jì)系列》的第六講(http://www.reibang.com/p/a5d0cde549...
    大魚Whale閱讀 951評(píng)論 0 1
  • 文/長今 敲不出的字 是梗在心里的話 停不下的雨 是落在回憶的淚 我們不過普通朋友 不過樹上兩片葉子 要隨風(fēng)飄 怎...
    我是長今閱讀 186評(píng)論 0 0
  • 曹操再奸叫确,都有知心朋友跳芳,劉備再好,都有死對(duì)頭竹勉,孫權(quán)再溫柔飞盆,兩邊都是仇。不要太在乎別人對(duì)你的評(píng)價(jià)次乓,做好自己的事吓歇,走好...
    天使思雅閱讀 244評(píng)論 0 0