以太坊原始碼解讀(4)Block類及其儲存
一、Block類
type Block struct { /******header*******/ header *Header /******header*******/ /******body*********/ uncles []*Header transactions Transactions /******body*********/ // 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{} }
block類實際上就只有兩個部分,header和body。其他的如hash、size、td等都是在接受和驗證區塊後產生的內容,實際上向全網公佈的時候block就只有header和body(uncles和transactions)。
Header裡有哪些內容呢?
type Header struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` Coinbase common.Address `json:"miner" gencodec:"required"` Root common.Hash `json:"stateRoot" gencodec:"required"` TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Difficulty *big.Int `json:"difficulty" gencodec:"required"` Number *big.Int `json:"number" gencodec:"required"` GasLimit uint64 `json:"gasLimit" gencodec:"required"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` Time *big.Int `json:"timestamp" gencodec:"required"` Extra []byte `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash" gencodec:"required"` Nonce BlockNonce `json:"nonce" gencodec:"required"` }
1)ParentHash:前一個區塊的hash
2)UncleHash:叔區塊hash,如果有多個叔區塊就加到一起
3)Coinbase:礦工賬戶
4)Root:StateDB中的“state Trie”的根節點的RLP雜湊值。
5)TxHash:“tx Trie”的根節點的RLP雜湊值。
6)ReceiptHash: "Receipt Trie”的根節點的RLP雜湊值。
7)Bloom:Bloom過濾器(Filter),用來快速判斷一個引數Log物件是否存在於一組已知的Log集合中。
8)Difficulty:難度值
9)Number:區塊號
10)GasLimit:區塊內所有Gas消耗的理論上限。該數值在區塊建立時設定,與父區塊的GasUsed有關。
11)GasUsed:
12)Time:時間戳
13)Extra:額外資訊
14)Nonce:pow產生的數值,也可以用於驗證礦工的工作
二、Root、TxHash、ReceiptHash
在比特幣中,區塊body中的交易通過merkle tree的形式組織,然後將merkle root存在block header中。
而在以太坊中不是merkle-tree,而是Merkle-PatricaTrie(MPT)結構,而且存在三棵樹:state Trie、tx Trie、Receipt Trie。
首先,在StateDB中,每個賬戶以stateObject物件表示,所有賬戶物件可以逐個插入一個Merkle-PatricaTrie(MPT)結構裡,形成“state Trie”。其次,Block的transactions中所有的tx物件,被逐個插入一個MPT結構,形成“tx Trie”。最後,所有Transaction執行完後會生成一個Receipt陣列,這個陣列中的所有Receipt被逐個插入一個MPT結構中,形成"Receipt Trie"。
上圖中表示的意思是,首先一個區塊的幾個重要部分分開儲存在leveldb中,header、body、receipts以RLP編碼的形式儲存在資料庫中,key都是用num+key構成的。另外,我們可以通過‘h’+num+hash+'t'查詢區塊鏈的總難度td;‘H’+hash可以查詢到blocknumber;在知道num的情況下可以查詢‘h’+num+‘n’對應的區塊鏈上的hash(即不在規範鏈上的區塊可能也有該num,但是無法通過這個key查詢到);在僅僅知道hash的情況下,通過‘l’+hash來查詢區塊hash+區塊號+交易編碼的編碼值,這樣的值僅僅儲存規範鏈上的區塊,所以我們可以快速的檢視某hash對應的區塊是否在規範鏈上。
key | value |
'h' + num +hash | header的RLP編碼值 |
'b' + num +hash | body的RLP編碼值 |
'r' + num +hash | receipt的RLP編碼值 |
'h' + num + hash + 't' | 截止該區塊的總難度值 |
'h' + num + 'n' | 區塊號對應的規範鏈上的區塊的hash(規範鏈 ) |
'H' + hash | Header對應的block number(規範鏈) |
'l' + hash | 【區塊hash、區塊號num、交易編號】的編碼值,是交易查詢入口(規範鏈) |
這些資訊都在強烈的暗示,num(Number)和hash是Block最為重要的兩個屬性:num用來確定Block在整個區塊鏈中所處的位置,hash用來辨識惟一的Block/Header物件。
通過以上的設計,Block結構體的所有重要成員,都被儲存進了底層資料庫。當所有Block物件的資訊都已經寫進資料庫後,我們就可以使用BlockChain結構體來處理整個塊鏈。