以太坊MPT數(shù)據(jù)結(jié)構(gòu)介紹

引言

go-etherum的包trie實現(xiàn)了Merkle Patricia Tries考榨,這里用簡稱MPT來稱呼這種數(shù)據(jù)結(jié)構(gòu)辈灼,這種數(shù)據(jù)結(jié)構(gòu)實際上是一種Trie樹變種,MPT是以太坊中一種非常重要的數(shù)據(jù)結(jié)構(gòu)纯赎,用來存儲用戶賬戶的狀態(tài)及其變更块攒、交易信息励稳、交易的收據(jù)信息。MPT實際上是三種數(shù)據(jù)結(jié)構(gòu)的組合囱井,分別是Trie樹驹尼, Patricia Trie, 和Merkle樹庞呕。

Trie樹 (引用自數(shù)據(jù)結(jié)構(gòu)之Trie樹)

Trie樹新翎,又稱字典樹,單詞查找樹或者前綴樹,是一種用于快速檢索的多叉樹結(jié)構(gòu)料祠,如英文字母的字典樹是一個26叉樹骆捧,數(shù)字的字典樹是一個10叉樹澎羞。

Trie樹可以利用字符串的公共前綴來節(jié)約存儲空間髓绽。如下圖所示,該trie樹用10個節(jié)點保存了6個字符串:tea妆绞,ten顺呕,to,in括饶,inn株茶,int:


Trie.jpg

在該trie樹中,字符串in图焰,inn和int的公共前綴是“in”启盛,因此可以只存儲一份“in”以節(jié)省空間。當然技羔,如果系統(tǒng)中存在大量字符串且這些字符串基本沒有公共前綴僵闯,則相應(yīng)的trie樹將非常消耗內(nèi)存,這也是trie樹的一個缺點藤滥。

Trie樹的基本性質(zhì)可以歸納為:

  • 根節(jié)點不包含字符鳖粟,除根節(jié)點以外每個節(jié)點只包含一個字符。
  • 從根節(jié)點到某一個節(jié)點拙绊,路徑上經(jīng)過的字符連接起來向图,為該節(jié)點對應(yīng)的字符串。
  • 每個節(jié)點的所有子節(jié)點包含的字符串不相同标沪。

Trie樹的優(yōu)缺點:

缺點:

  • 當 hash 函數(shù)很好時榄攀,Trie樹的查找效率會低于哈希搜索。
  • 空間消耗比較大金句。

優(yōu)點:

  • 插入和查詢的效率很高檩赢,都為O(m),其中 m 是待插入/查詢的字符串的長度漠畜。
  • Trie樹中不同的關(guān)鍵字不會產(chǎn)生沖突。
  • Trie樹只有在允許一個關(guān)鍵字關(guān)聯(lián)多個值的情況下才有類似hash碰撞發(fā)生。
  • Trie樹不用求 hash 值庆杜,對短字符串有更快的速度典蜕。通常钢猛,求hash值也是需要遍歷字符串的火的。
  • Trie樹可以對關(guān)鍵字按字典序排序假瞬。

Patricia 樹 (引用自深入淺出以太坊)

Patricia樹,或稱Patricia trie,或crit bit tree箭券,壓縮前綴樹荆永,是一種更節(jié)省空間的Trie液兽。對于基數(shù)樹的每個節(jié)點坏匪,如果該節(jié)點是唯一的兒子的話罚屋,就和父節(jié)點合并嗅绸。

Patricia.png

Patricia優(yōu)缺點:

優(yōu)點:Patricia Trie相比Trie優(yōu)點明顯脾猛,減少了空間的消耗。

缺點:隨著后續(xù)節(jié)點的不斷插入和刪除鱼鸠,原有節(jié)點可能會發(fā)生變化猛拴,并有可能不斷裂變或者合并出新的節(jié)點

Merkle 樹 (引用自深入淺出以太坊)

Merkle Tree,通常也被稱作Hash Tree蚀狰,顧名思義愉昆,就是存儲hash值的一棵樹。Merkle樹的葉子是數(shù)據(jù)塊(例如麻蹋,文件或者文件的集合)的hash值跛溉。非葉節(jié)點是其對應(yīng)子節(jié)點串聯(lián)字符串的hash。

要了解Merkle Tree就要先從Hash List說起:

在點對點網(wǎng)絡(luò)中作數(shù)據(jù)傳輸?shù)臅r候扮授,會同時從多個機器上下載數(shù)據(jù)芳室,而且很多機器可以認為是不穩(wěn)定或者不可信的。為了校驗數(shù)據(jù)的完整性刹勃,更好的辦法是把大的文件分割成小的數(shù)據(jù)塊(例如堪侯,把分割成2K為單位的數(shù)據(jù)塊)。這樣的好處是深夯,如果小塊數(shù)據(jù)在傳輸過程中損壞了抖格,那么只要重新下載這一快數(shù)據(jù)就行了诺苹,不用重新下載整個文件。

怎么確定小的數(shù)據(jù)塊沒有損壞哪雹拄?只需要為每個數(shù)據(jù)塊做Hash收奔。BT下載的時候,在下載到真正數(shù)據(jù)之前滓玖,我們會先下載一個Hash列表坪哄。那么問題又來了,怎么確定這個Hash列表本身是正確的呢势篡?答案是把每個小塊數(shù)據(jù)的Hash值拼到一起翩肌,然后對這個長字符串再做一次Hash運算,這樣就得到Hash列表的根Hash(Top Hash or Root Hash)禁悠。下載數(shù)據(jù)的時候念祭,首先從可信的數(shù)據(jù)源得到正確的根Hash,就可以用它來校驗Hash列表了碍侦,然后通過校驗后的Hash列表校驗數(shù)據(jù)塊粱坤。

Hash List.png

Merkle Tree可以看做Hash List的泛化(Hash List可以看作一種特殊的Merkle Tree,即樹高為2的多叉Merkle Tree瓷产。

在最底層站玄,和哈希列表一樣,我們把數(shù)據(jù)分成小的數(shù)據(jù)塊濒旦,有相應(yīng)地哈希和它對應(yīng)株旷。但是往上走,并不是直接去運算根哈希尔邓,而是把相鄰的兩個哈希合并成一個字符串晾剖,然后運算這個字符串的哈希,這樣每兩個哈希就結(jié)婚生子铃拇,得到了一個”子哈铣伲“。如果最底層的哈峡独螅總數(shù)是單數(shù)雕什,那到最后必然出現(xiàn)一個單身哈希,這種情況就直接對它進行哈希運算显晶,所以也能得到它的子哈希贷岸。于是往上推,依然是一樣的方式磷雇,可以得到數(shù)目更少的新一級哈希偿警,最終必然形成一棵倒掛的樹,到了樹根的這個位置唯笙,這一代就剩下一個根哈希了螟蒸,我們把它叫做 Merkle Root盒使。

Merkle Tree.png

在p2p網(wǎng)絡(luò)下載網(wǎng)絡(luò)之前,先從可信的源獲得文件的Merkle Tree樹根七嫌。一旦獲得了樹根少办,就可以從其他從不可信的源獲取Merkle tree。通過可信的樹根來檢查接受到的MerkleTree诵原。如果Merkle Tree是損壞的或者虛假的英妓,就從其他源獲得另一個Merkle Tree,直到獲得一個與可信樹根匹配的MerkleTree绍赛。

Merkle Tree和HashList的主要區(qū)別是蔓纠,可以直接下載并立即驗證Merkle Tree的一個分支。因為可以將文件切分成小的數(shù)據(jù)塊吗蚌,這樣如果有一塊數(shù)據(jù)損壞腿倚,僅僅重新下載這個數(shù)據(jù)塊就行了。如果文件非常大褪测,那么Merkle tree和Hash list都很到猴誊,但是Merkle tree可以一次下載一個分支,然后立即驗證這個分支侮措,如果分支驗證通過,就可以下載數(shù)據(jù)了乖杠。而Hash list只有下載整個hash list才能驗證分扎。

MPT

Trie結(jié)構(gòu)

MPT 是 Ethereum 自定義的 Trie 型數(shù)據(jù)結(jié)構(gòu)。在代碼中胧洒,trie.Trie 結(jié)構(gòu)體用來管理一個 MPT 結(jié)構(gòu)畏吓,其中每個節(jié)點都是行為接口 Node 的實現(xiàn)類。下圖是 Trie 結(jié)構(gòu)體和 node 接口族的 UML 關(guān)系圖:

Trie.png
  • 在 Trie 結(jié)構(gòu)體中卫漫,成員 root 始終作為整個 MPT 的根節(jié)點;

  • db是后端的KV存儲菲饼,trie的結(jié)構(gòu)最終都是需要通過KV的形式存儲到數(shù)據(jù)庫里面去,然后啟動的時候是需要從數(shù)據(jù)庫里面加載的;

  • originalRoot 的作用是在創(chuàng)建 Trie 對象時承接入?yún)?hashNode列赎,通過這個hash值可以在數(shù)據(jù)庫里面恢復出整顆的trie樹;

  • cachegen 是 cache 次數(shù)的計數(shù)器宏悦,每次 Trie 的變動提交后cachegen 自增 1。

    cachegen會被附加在node節(jié)點上面(node.nodeFlag.gen)包吝,默認等于Trie的cachegen饼煞。如果Trie每次Commit的時候node有更新,那么Trie的cachegen會重新賦值給node的cachegen诗越。否則node的cachegen將小于Trie的cachegen砖瞧。
    如果當前Trie的cachegen - cachelimit大于node的cachegen,說明trie提交了cachelimit次之后嚷狞,node一直沒有更新块促。那么node會從cache里面卸載荣堰,以便節(jié)約內(nèi)存。 其實這就是緩存更新的LRU算法竭翠, 如果一個緩存在多久沒有被使用持隧,那么就從緩存里面移除,以節(jié)約內(nèi)存空間逃片。

  • Trie 結(jié)構(gòu)體提供包括對節(jié)點的插入屡拨、刪除、更新褥实,所有節(jié)點改動的提交呀狼,以及返回整個 MPT 的哈希值。

node

node 接口族擔當整個 MPT 中的各種節(jié)點损离,node 接口分四種實現(xiàn): fullNode哥艇,shortNode,valueNode僻澎,hashNode貌踏,其中只有 fullNode 和 shortNode 可以帶有子節(jié)點。

fullNode 是一個可以攜帶多個子節(jié)點的節(jié)點窟勃。

  • 它有一個容量為 17 的 node 數(shù)組成員變量 Children
  • 數(shù)組中前 16 個空位分別對應(yīng) 16 進制 (hex) 下的 0-9a-f祖乳,這樣對于每個子節(jié)點,根據(jù)其 key 值 16 進制形式下的第一位的值秉氧,就可掛載到 Children 數(shù)組的某個位置眷昆,fullNode 本身不再需要額外 key 變量;
  • Children 數(shù)組的第 17 位汁咏,留給該 fullNode 的數(shù)據(jù)部分亚斋。fullNode 明顯繼承了原生 trie 的特點,而每個父節(jié)點最多擁有 16 個分支也包含了基于總體效率的考量攘滩。

shortNode 是一個僅有一個子節(jié)點的節(jié)點帅刊。

  • 它的成員變量 Val 指向一個子節(jié)點,而成員 Key 是一個字節(jié)數(shù)組[]byte漂问。
  • 顯然 shortNode 的設(shè)計體現(xiàn)了 PatriciaTrie 的特點赖瞒,通過合并只有一個子節(jié)點的父節(jié)點和其子節(jié)點來縮短 trie 的深度。

valueNode 承載了MPT結(jié)構(gòu)中 真正數(shù)據(jù)部分的節(jié)點级解。

  • 它其實是字節(jié)數(shù)組 []byte 的一個別名冒黑,不帶子節(jié)點。
  • 在使用中勤哗,valueNode 就是所攜帶數(shù)據(jù)部分的 RLP 哈希值抡爹,長度 32byte,數(shù)據(jù)的 RLP 編碼值作為 valueNode 的匹配項存儲在數(shù)據(jù)庫里芒划。

這三種類型構(gòu)成了一個完整的PatriciaTrie結(jié)構(gòu)冬竟。何一個[k,v]類型數(shù)據(jù)被插入一個MPT時欧穴,會以k字符串為路徑沿著root向下延伸,在此次插入結(jié)束時首先成為一個shortNode泵殴,k會以自頂點root起到到該節(jié)點止的key path形式存在涮帘。但之后隨著其他節(jié)點的不斷插入和刪除,根據(jù)MPT結(jié)構(gòu)的要求笑诅,原有節(jié)點可能會變化成其他node實現(xiàn)類型调缨,同時MPT中也會不斷裂變或者合并出新的節(jié)點。

注意:黃皮書中把節(jié)點類型概括為了分支節(jié)點吆你、擴展節(jié)點和葉子節(jié)點弦叶。fullNode對應(yīng)了黃皮書里面的分支節(jié)點,shortNode對應(yīng)了黃皮書里面的擴展節(jié)點和葉子節(jié)點(通過shortNode.Val的類型來對應(yīng)到底是葉子節(jié)點還是分支節(jié)點妇多,如果是valueNode伤哺,就是葉子節(jié)點,否則是分支節(jié)點)者祖。

hashNode
hashNode 跟 valueNode 一樣立莉,也是字符數(shù)組 []byte 的一個別名,同樣存放 32byte 的哈希值七问,也沒有子節(jié)點蜓耻。不同的是,hashNode 是 fullNode 或者 shortNode 對象的 RLP 哈希值烂瘫,所以它跟 valueNode 在使用上有著莫大的不同媒熊。

在 MPT 中,hashNode 幾乎不會單獨存在 (有時遍歷遇到一個 hashNode 往往因為原本的 node 被折疊了)坟比,而是以 nodeFlag 結(jié)構(gòu)體的成員(nodeFlag.hash) 的形式,被 fullNode 和 shortNode 間接持有嚷往。一旦 fullNode 或 shortNode 的成員變量 (包括子結(jié)構(gòu)) 發(fā)生任何變化葛账,它們的 hashNode 就一定需要更新。所以在 trie.Trie 結(jié)構(gòu)體的 insert()皮仁,delete()等函數(shù)實現(xiàn)中籍琳,可以看到除了新創(chuàng)建的 fullNode、shortNode贷祈,那些子結(jié)構(gòu)有所改變的 fullNode趋急、shortNode 的 nodeFlag 成員也會被重設(shè),hashNode 會被清空势誊。在下次 trie.Hash()調(diào)用時呜达,整個 MPT 自底向上的遍歷過程中,所有清空的 hashNode 會被重新賦值粟耻。這樣 trie.Hash()結(jié)束后查近,我們可以得到一個根節(jié)點 root 的 hashNode眉踱,它就是此時此刻這個 MPT 結(jié)構(gòu)的哈希值。上文中提到的霜威,Block 的成員變量 Root谈喳、TxHash、ReceiptHash 的生成戈泼,正是源出于此婿禽。

明顯的,hashNode 體現(xiàn)了 MerkleTree 的特點:每個父節(jié)點的哈希值來源于所有子節(jié)點哈希值的組合大猛,一個頂點的哈希值能夠代表一整個樹形結(jié)構(gòu)扭倾。

hashNode 加上之前的 fullNode,shortNode胎署,valueNode吆录,構(gòu)成了一個完整的 Merkle-PatriciaTrie 結(jié)構(gòu)。

一個MPT簡單例子:


MPT.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琼牧,一起剝皮案震驚了整個濱河市恢筝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巨坊,老刑警劉巖撬槽,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趾撵,居然都是意外死亡侄柔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門占调,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暂题,“玉大人,你說我怎么就攤上這事究珊⌒秸撸” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵剿涮,是天一觀的道長言津。 經(jīng)常有香客問我,道長取试,這世上最難降的妖魔是什么悬槽? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮瞬浓,結(jié)果婚禮上初婆,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好烟逊,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布渣窜。 她就那樣靜靜地躺著,像睡著了一般宪躯。 火紅的嫁衣襯著肌膚如雪乔宿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天访雪,我揣著相機與錄音详瑞,去河邊找鬼。 笑死臣缀,一個胖子當著我的面吹牛坝橡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播精置,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼计寇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脂倦?” 一聲冷哼從身側(cè)響起番宁,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赖阻,沒想到半個月后蝶押,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡火欧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年棋电,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苇侵。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡赶盔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榆浓,到底是詐尸還是另有隱情招刨,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布哀军,位于F島的核電站,受9級特大地震影響打却,放射性物質(zhì)發(fā)生泄漏杉适。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一柳击、第九天 我趴在偏房一處隱蔽的房頂上張望猿推。 院中可真熱鬧,春花似錦、人聲如沸蹬叭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秽五。三九已至孽查,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坦喘,已是汗流浹背盲再。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瓣铣,地道東北人答朋。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像棠笑,于是被迫代替她去往敵國和親梦碗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容