以太坊系列---Block核心資料結構
在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
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資料。