@
MPT樹定義
一種經過改良的、融合了默克爾樹和前綴樹兩種樹結構優點的數據結構,以太坊中,MPT是一個非常重要的數據結構,在以太坊中,帳戶的交易信息、狀態以及相應的狀態變更,還有相關的交易信息等都使用MPT來進行管理,其是整個數據存儲的重要一環。交易樹,收據樹,狀態樹都是采用的MPT結構。
ps:
- 交易樹:記錄交易的狀態和變化。每個塊都有各自的交易樹,且不可更改
- 收據樹(交易收據):交易收據的存儲
- 狀態樹(賬戶信息):帳戶中各種狀態的保存。如余額等。
- Storage Trie 存儲樹 :存儲只能合約狀態 ,每個賬號有自己的Storage Trie 。
回想我們我們上一次所講的RLP:
在網絡節點的本地以trie樹的形式存儲,發送給客戶端的時候序列化成列表。這不就是RLP的作用嘛,用來對trie樹種所有的條目進行編碼
這個樹,在以太坊,指的就MPT樹
MPT樹的作用是什么?
- 存儲任意長度的key-value鍵值對數據;
- 提供了一種快速計算所維護數據集哈希標識的機制;
- 提供了快速狀態回滾的機制;
- 提供了一種稱為默克爾證明的證明方法,進行輕節點的擴展,實現簡單支付驗證;
前綴樹與默克爾樹
前綴樹
前綴樹(又稱字典樹),用於保存關聯數組,其鍵(key)的內容通常為字符串。前綴樹節點在樹中的位置是由其鍵的內容所決定的,即前綴樹的key值被編碼在根節點到該節點的路徑中。
如下圖所示,圖中共有6個葉子節點,其key的值分別為(1)to(2)tea(3)ted(4)ten(5)A(6)inn。
默克爾樹
merkle樹是自底向上構建的。在下圖的例子中,首先將L1-L4四個單元數據哈希化,然后將哈希值存儲至相應的葉子節點。
將相鄰兩個節點的哈希值合並成一個字符串,然后計算這個字符串的哈希,得到的就是這兩個節點的父節點的哈希值。
重要結論:
若兩棵樹的根哈希一致,則這兩棵樹的結構、節點的內容必然相同。
分析:
在p2p網絡下載網絡之前,先從可信的源獲得文件的Merkle Tree樹根。一旦獲得了樹根,就可以從其他從不可信的源獲取Merkle tree。通過可信的樹根來檢查接受到的MerkleTree。如果Merkle Tree是損壞的或者虛假的,就從其他源獲得另一個Merkle Tree,直到獲得一個與可信樹根匹配的MerkleTree。
三種節點類型
知道了Merkle Tree,知道了Patricia Tree,MPT(Merkle Patricia Tree)就是這兩者混合后的產物。下面我們介紹一下MPT樹的三種節點類型
- 分支結點(branch node):包含16個分支,以及1個value
- 擴展結點(extension node):只有1個子結點
- 葉子結點(leaf node):沒有子結點,包含一個value
需要注意的是:Key-value 這里的value存儲的是key,key存儲在路徑上
詳細解釋:
葉子節點,表示為[key,value]的一個鍵值對,其中key是key的一種特殊十六進制編碼。
擴展節點,也是[key,value]的一個鍵值對,但是這里的value是其他節點的hash值,這個hash可以被用來查詢數據庫中的節點。也就是說通過hash鏈接到其他節點。
分支節點,因為MPT樹中的key被編碼成一種特殊的16進制的表示,再加上最后的value,所以分支節點是一個長度為17的list,前16個元素對應着key中的16個可能的十六進制字符,如果有一個[key,value]對在這個分支節點終止,最后一個元素代表一個值,即分支節點既可以搜索路徑的終止也可以是路徑的中間節點。
葉子節點和擴展節點是新增加的!(對比於前綴樹來說)
MPT中的Merkle
即指向下一級節點的指針是使用 節點的確定性加密hash,而不是傳統意義上下一級節點地址的指針
如果給定的trie的根哈希是公開的,則任何人都可以 通過給出給定path上的所有節點, 來證明在給定path上存在一個給定值 ,對於攻擊者,不可能提供一個不存在的(key,value)對的證明, 因為根哈希最終基於它下面的所有哈希,所以任何修改都會改變根哈希。
HP編碼
HP-編碼:特殊的十六進制前綴編碼
引入:對nibble和節點奇偶性進行編碼
Nibble是什么?
引進一種特殊的終止符標識來標識key所對應的是值是真實的值,還是其他節點的hash。如果終止符標記被打開,那么key對應的是葉節點,對應的值是真實的value。如果終止符標記被關閉,那么值就是用於在數據塊中查詢對應的節點的hash。
為什么需要對節點奇偶性進行編碼?
數據最小的表示單位為一位16進制,如1、a等,但在編程實現中,數據的最小表示單位往往是byte(8bit,2位16進制數),這樣在用byte來表示一串奇數長度的16進制串時會出現問題。
例如"5b3"和"5b30",直接轉成byte都是5b30。
舉例:
對"0x5b3ed"編碼(奇數位)
"0x5b3ed" = "0005 1011 0003 1110 1101"t=0 時, "0001"+"0005 1011 0003 1110 1101"->"00010005 10110003 11101101"->"0x15b3ed"
t !=0時 "0011"+"0005 1011 0003 1110 1101"->"00110005 10110003 11101101"->"0x35b3ed“
對"0x5b3e"編碼(偶數位)
"0x5b3e" = "0005 1011 0003 1110"t=0 時, "0000"+"0005 1011 0003 1110 1101"->"00000005 10110003 11101101"->"0x005b3e"
t !=0時 "0010"+"0005 1011 0003 1110 1101"->"00100005 10110003 11101101"->"0x205b3e"
這里的t就是是否結束的標志位
最低位表示奇偶性,第二低位編碼終止符狀態。
最低位為0的時候表示偶數位置,反之奇數。
第二低位為1的時候表示結束,反之不結束。
官方表示形式
這里的prefix就是HP編碼!對終止符的狀態和奇偶性進行編碼。最低位表示奇偶性,第二低位編碼終止符狀態。
總共有2個擴展節點,2個分支節點,4個葉子節點。 右邊是葉子節點的情況,左邊代表的是節點的prefix(HP編碼)
這就是一個狀態樹的存儲形式,其實他應當長的樣子,我們可以細細想一下,他的key被編碼成一種特殊的16進制的表示,value是一些rlp后的數據,而且比上圖要大的多的多。
相關MPT樹
現在,我們來回看一下,狀態、存儲以及交易樹使用的MPT樹。
首先說,全局狀態樹,這個全局狀態樹包含了以太坊網絡中每一個賬戶的一組鍵值對。
對全局狀態樹的幾點說明:
- 狀態前綴樹包含了以太坊網絡中每一個賬戶的一組鍵值對。
- 他的Key是一個 160 位的標識符(以太坊賬戶的地址)。
- 全局狀態樹中的 “值” 是通過編碼以太坊賬戶中的如下細節來得到的(使用RLP的方法):
- nonce 值
- 余額
- 存儲前綴樹根節點哈希
- 代碼哈希
我們可以從下圖很清晰的了解:
存儲樹是智能合約數據存儲的位置,每一個以太坊賬戶都有自己的存儲樹。
本圖接上圖;
參考目錄
[1]. 深入淺出以太坊MPT(Merkle Patricia Tree)
[2]. 以太坊學習(2)MPT樹--白話版
[3]. Merkle Patricia Tree 梅克爾帕特里夏樹(MPT)規范
[4]. merkle樹、Trie樹、MPT樹、以太坊中的那些樹