在Ethereum的世界裡,資料的最終儲存形式是[k,v]鍵值對,目前使用的[k,v]型底層資料庫是LevelDB;所有與交易,操作相關的資料,其呈現的集合形式是Block(Header);如果以Block為單位連結起來,則構成更大粒度的BlockChain(HeaderChain);若以Block作切割,那麼Transaction和Contract就是更小的粒度;所有交易或操作的結果,將以各個個體賬戶的狀態(state)存在,賬戶的呈現形式是stateObject,所有賬戶的集合受StateDB管理。下圖描繪了上述各資料單元的層次關係:
另一方面,上述資料單元如Block,stateObject,StateDB等,均大量使用Merkle-PatriciaTrie(MPT)資料結構以組織和管理[k,v]型資料。利用MPT高效的分段雜湊驗證機制和靈活的節點(Node)插入/載入設計,呼叫方均可快速且高效的實現對資料的插入、刪除、更新、壓縮和加密。

Block和Header

Block結構體基本可分為Header和Body兩個部分

Header是Block的核心,注意到它的成員變數全都是公共的,這使得它可以很方便的向呼叫者提供關於Block屬性的操作。Header的成員變數全都很重要,值得細細理解:

  • ParentHash:指向父區塊(parentBlock)的指標。除了創世塊(Genesis Block)外,每個區塊有且只有一個父區塊。
  • Coinbase:挖掘出這個區塊的作者地址。在每次執行交易時系統會給與一定補償的Ether,這筆金額就是發給這個地址的。
  • UncleHash:Block結構體的成員uncles的RLP雜湊值。uncles是一個Header陣列,它的存在,頗具匠心。
  • Root:StateDB中的“state Trie”的根節點的RLP雜湊值。Block中,每個賬戶以stateObject物件表示,賬戶以Address為唯一標示,其資訊在相關交易(Transaction)的執行中被修改。所有賬戶物件可以逐個插入一個Merkle-PatricaTrie(MPT)結構裡,形成“state Trie”。
  • TxHash: Block中 “tx Trie”的根節點的RLP雜湊值。Block的成員變數transactions中所有的tx物件,被逐個插入一個MPT結構,形成“tx Trie”。
  • ReceiptHash:Block中的 “Receipt Trie”的根節點的RLP雜湊值。Block的所有Transaction執行完後會生成一個Receipt陣列,這個陣列中的所有Receipt被逐個插入一個MPT結構中,形成”Receipt Trie”。
  • Bloom:Bloom過濾器(Filter),用來快速判斷一個引數Log物件是否存在於一組已知的Log集合中。
  • **Difficulty:區塊的難度。Block的Difficulty由共識演算法基於parentBlock的Time和Difficulty計算得出,它會應用在區塊的‘挖掘’階段。
  • Number:區塊的序號。Block的Number等於其父區塊Number +1。
  • Time:區塊“應該”被建立的時間。由共識演算法確定,一般來說,要麼等於parentBlock.Time + 10s,要麼等於當前系統時間。
  • GasLimit:區塊內所有Gas消耗的理論上限。該數值在區塊建立時設定,與父區塊有關。具體來說,根據父區塊的GasUsed同GasLimit * 2/3的大小關係來計算得出。
  • GasUsed:區塊內所有Transaction執行時所實際消耗的Gas總和。
  • Nonce:一個64bit的雜湊數,它被應用在區塊的”挖掘”階段,並且在使用中會被修改。

Root,TxHash和ReceiptHash,分別取自三個MPT型別物件:stateTrie, txTrie, 和receiptTrie的根節點雜湊值。
receiptTrie 必須在Block的所有交易執行完成才能生成;txTrie 理論上只需tx陣列transactions即可,不過依然被限制在所有交易執行完後才生成;最有趣的是stateTrie,由於它儲存了所有賬戶的資訊,比如餘額,發起交易次數,虛擬機器指令陣列等等,所以隨著每次交易的執行,stateTrie 其實一直在變化,這就使得Root值也在變化中。

Bloom:日誌布隆過濾器 2048bit 256位元組
使用者可以通過傳遞下面的引數來查詢指定的Log,開始的區塊號,結束的區塊號, 根據合約 Addresses指定的地址過濾,根據指定的Topics來過濾。

BlockChain

type BlockChain struct {
    config *params.ChainConfig // chain & network configuration

    hc            *HeaderChain      // 只包含了區塊頭的區塊鏈
    chainDb       ethdb.Database    // 底層資料庫
    rmLogsFeed    event.Feed        // 下面是很多訊息通知的元件
    chainFeed     event.Feed
    chainSideFeed event.Feed
    chainHeadFeed event.Feed
    logsFeed      event.Feed
    scope         event.SubscriptionScope
    genesisBlock  *types.Block      // 創世區塊

    mu      sync.RWMutex // global mutex for locking chain operations
    chainmu sync.RWMutex // blockchain insertion lock
    procmu  sync.RWMutex // block processor lock

    checkpoint       int          // checkpoint counts towards the new checkpoint
    currentBlock     *types.Block //  當前的區塊頭
    currentFastBlock *types.Block // 當前的快速同步的區塊頭.

    stateCache   state.Database // State database to reuse between imports (contains state cache)
    bodyCache    *lru.Cache     // Cache for the most recent block bodies
    bodyRLPCache *lru.Cache     // Cache for the most recent block bodies in RLP encoded format
    blockCache   *lru.Cache     // Cache for the most recent entire blocks
    futureBlocks *lru.Cache     // 暫時還不能插入的區塊存放位置.

    quit    chan struct{} // blockchain quit channel
    running int32         // running must be called atomically
    // procInterrupt must be atomically called
    procInterrupt int32          // interrupt signaler for block processing
    wg            sync.WaitGroup // chain processing wait group for shutting down

    engine    consensus.Engine  // 一致性引擎
    processor Processor // block processor interface  // 區塊處理器介面
    validator Validator // block and state validator interface // 區塊和狀態驗證器介面
    vmConfig  vm.Config //虛擬機器的配置

    badBlocks *lru.Cache // Bad block cache  錯誤區塊的快取.
}

小結

以太坊的賬號模型相對於比特幣UTXO模型更加複雜。需要維護日誌,StateDB,賬號餘額等資料,值得去深入學習使用。

  • Block結構體主要分為Header和Body,Header相對輕量,涵蓋了Block的所有屬性,包括特徵標示,前向指標,和內部資料集的驗證雜湊值等;Body相對重量,持有內部資料集。每個Block的Header部分,Body部分,以及一些特徵屬性,都以[k,v]形式單獨儲存在底層資料庫中。
  • BlockChain管理Block組成的一個單向連結串列,HeaderChain管理Header組成的單向連結串列,並且BlockChain持有HeaderChain。在做插入/刪除/查詢時,要注意回溯,以及資料庫中相應的增刪。
  • Merkle-PatriciaTrie(MPT)資料結構用來組織管理[k,v]型資料,它設計了靈活多變的節點體系和編碼格式,既融合了多種原型結構的優點,又兼顧了業務需求和執行效率。
  • StateDB作為本地儲存模組,它面向業務模型,又連線底層資料庫,內部利用兩極快取機制來儲存和更新所有代表“賬戶”的stateObject物件。
  • stateObject除了管理著賬戶餘額等資訊之外,也用了類似的兩級快取機制來儲存和更新所有的State資料。