15-ETH-狀態樹

聲明:本文是要點筆記,介紹和系列筆記均收錄在專題:區塊鏈技術與應用

以太坊採用基於賬戶的模式,系統中顯式記錄每個賬戶的餘額。而以太坊這樣一個大型分佈式系統中,是採用的什麼樣的數據結構來實現對這些數據的管理的。

介紹

首先,我們要實現從賬戶地址到賬戶狀態的映射。在以太坊中,賬戶地址爲160字節,表示爲40個16進制數額。狀態包含了餘額(balance)、交易次數(nonce),合約賬戶中還包含了code(代碼)、存儲(stroge)。

直觀地來看,其本質上爲Key-value鍵值對,所以直觀想法便用哈希表實現。若不考慮哈希碰撞,查詢直接爲常數級別的查詢效率。但採用哈希表,難以提供Merkle proof(《02-BTC-數據結構》有講過)。

注意:在BTC和以太坊中,交易保存在區塊內部,一個區塊可以包含多個交易。通過區塊構成區塊鏈,而非交易。

想想如何組織賬戶的數據結構?
1、我們能否像 BTC 中,將哈希表的內容組織爲 Merkle Tree?

但當新區塊發佈,哈希表內容會改變,再次將其組織爲新的 Merkle Tree。如果這樣,每當產生新區塊(ETH中新區塊產生時間爲10s左右),都要重新組織 Merkle Tree,很明顯這是不現實的。

需要注意的是,比特幣系統中沒有賬戶概念,交易由區塊管理,而區塊包含上限爲4000個交易左右,所以Merkle Tree不是無限增大的。而 ETH 中,Merkle Tree來組織賬戶信息,很明顯其會越來越龐大。

實際中,發生變化的僅僅爲很少一部分數據,我們每次重新構建Merkle Tree代價很大。

2、那我們不要哈希表了,直接使用Merkle Tree,每次修改只需要修改其中一部分即可,這個可以嗎?

實際中,Merkle Tree並未提供一個高效的查找和更新的方案。此外,將所有賬戶構建爲一個大的Merkle Tree,爲了保證所有節點的一致性和查找速度,必須進行排序。

3、那麼經過排序,使用Sorted Merkle Tree可以嗎?

新增賬戶,由於其地址隨機,插入Merkle Tree時候很大可能在Tree中間,發現其必須進行重構。所以Sorted Merkle Tree插入、刪除(實際上可以不刪除)的代價太大。

既然哈希表和 Merkle Tree都不可以,那麼我們看一下實際中以太坊採取的數據結構:MPT

BTC 系統中,雖然每個節點構建的 Merkle Tree不一致(不排序),但最終是獲得記賬權的節點的 Merkle Tree纔是有效的。

數據結構——trie(字典樹、前綴樹)

上圖爲一個通過5個單詞組成的 trie 數據結構(只畫出key,未畫出value)。它有如下特點:

  1. trie 中每個節點的分支數目取決於Key值中每個元素的取值範圍(圖例中最多26個英文字母分叉+一個結束標誌位)。
  2. trie查找效率取決於key的長度。實際應用中(以太坊地址長度爲160byte)。
  3. 理論上哈希會出現碰撞,而 trie上面不會發生碰撞。
  4. 給定輸入,無論如何順序插入,構造的 trie 都是一樣的。
  5. 更新操作局部性較好。

那麼 trie 有缺點嗎?當然有:trie 的存儲浪費。很多節點只存儲一個key,但其子節點只有一個,過於浪費。因此,爲了解決這一問題,我們引入帕特麗夏樹(Patricia tree/trie)。

帕特麗夏樹(Patricia tree)

Patricia trie 就是進行了路徑壓縮的 trie。如上圖例子,進行路徑壓縮後如下圖所示:

需要注意的是,如果新插入單詞,原本壓縮的路徑可能需要擴展開來。那麼,需要考慮什麼情況下路徑壓縮效果較好?樹中插入的鍵值分佈較爲稀疏的情況下,可見路徑壓縮效果較好。

在以太坊系統中,160位的地址存在2^160 種,該數實際上已經非常大了,和賬戶數目相比,可以認爲地址這一鍵值非常稀疏。

因此,我們可以在以太坊賬戶管理種使用Patricia tree這一數據結構!但實際上,在以太坊種使用的並非簡單的PT(Patricia tree),而是MPT(Merkle Patricia tree)。

MPT(Merkle Patricia tree)

Merkle Tree 和 Binary Tree
區塊鏈和鏈表的區別在於區塊鏈使用哈希指針,鏈表使用普通指針。同樣,Merkle Tree 相比 Binary Tree,也是普通指針換成了哈希指針。

所以,以太坊系統可以這樣,將所有賬戶組織爲一個經過路徑壓縮和排序的 Merkle Tree,其根哈希值存儲於block header中。

注意,BTC 系統中只有一個交易組成的Merkle Tree,而以太坊中有三個(三棵樹)。也就是說,在以太坊的block header中,存在有三個根哈希值。

根哈希值的用處:

  1. 防止篡改。
  2. 提供 Merkle proof,可以證明賬戶餘額,輕節點可以進行驗證。
  3. 證明某個發生了交易的賬戶是否存在。

MPT(Merkle Patricia tree)
以太坊中針對MPT(Merkle Patricia tree)進行了修改,我們稱其爲MPT(Modified Patricia tree)

下圖爲以太坊中使用的 MPT 結構示意圖。右上角表示四個賬戶(爲直觀,顯示較短地址)和其狀態(只顯示賬戶餘額)。(需要注意這裏的指針都是哈希指針)

每次發佈新區塊,狀態樹中部分節點狀態會改變。但改變並非在原地修改,而是新建一些分支,保留原本狀態。如下圖中,僅僅有新發生改變的節點才需要修改,其他未修改節點直接指向前一個區塊中的對應節點。

所以,系統中全節點並非維護一棵MPT,而是每次發佈新區塊都要新建MPT。只不過大部分節點共享。

爲什麼要保存原本狀態?爲何不直接修改?爲了便於回滾。

以太坊中的數據結構

block header 數據結構

解釋:

  • parentHash:父區塊的哈希,即前一個區塊的哈希值
  • UncleHash:叔父區塊的哈希
  • Coinbase:礦工地址
  • Root:狀態樹根哈希
  • TxHash:交易樹根哈希
  • ReceiptHash:收據樹根哈希
  • Bloom:布隆過濾器,用於查詢,和收據樹相關
  • Difficulty:挖礦難度
  • Gaslimit、GasUsed:gas 費相關
  • Time:區塊大致產生的時間
  • MixDigest、Nonce:和挖礦過程相關

區塊結構

解釋:

  • header:執行 block header 的指針
  • uncles:指向叔父區塊的指針
  • transactions:交易列表

區塊在網上真正發佈時的信息

最後說明

狀態樹中保存Key-value對,key就是地址,而value狀態通過RLP(Recursive Length Prefix,一種進行序列化的方法)編碼序列號之後再進行存儲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章