1. 程式人生 > >IPFS資料結構Merkle DAG

IPFS資料結構Merkle DAG

本文的提綱:

一、Hash(雜湊)

二、Hash List(雜湊列表)

三、Merkle Tree(默克爾樹)

四、Merkle DAG(Merkle directed acyclic graph,默克爾有向無環圖)

一、Hash(雜湊)

Hash是一個函式,它把任意長度的資料作為輸入,對映成固定長度的輸出。例如,對於資料完整性校驗,最簡單的方法是對整個資料做Hash運算得到固定長度的Hash值,然後把得到的Hash值公佈在網上,這樣使用者下載到資料之後,對資料再次進行Hash運算,比較運算結果和網上公佈的Hash值進行比較,如果兩個Hash值相等,說明下載的資料沒有損壞。之所以可以這樣做,是因為雜湊函式的兩個重要特徵:一是輸入資料的微小改變就會引起Hash運算結果的重大改變,二是根據Hash輸出反推原始輸入資料是非常困難的。

二、Hash List(雜湊列表)

在點對點網路中作資料傳輸的時候,會同時從多個機器上下載資料,而且很多機器可以認為是不穩定或者不可信的。為了校驗資料的完整性,更好的辦法是把大的檔案分割成小的資料塊(例如,把分割成256K為單位的資料塊)。這樣的好處是,如果小塊資料在傳輸過程中損壞了,那麼只要重新下載這一快資料就行了,不用重新下載整個檔案。

怎麼確定小的資料塊沒有損壞呢?只需要為每個資料塊做Hash。BT下載的時候,在下載到真正的完整資料之前,我們會先下載一個Hash列表。那麼問題又來了,怎麼確定這個Hash列表本身是正確的哪?答案是把每個小塊資料的Hash值拼到一起,然後對這個長字串再作一次Hash運算,這樣就得到Hash列表的根Hash(Top Hash or Root Hash)。下載資料的時候,首先從可信的資料來源得到正確的根Hash,就可以用它來校驗Hash列表了,然後通過校驗後的Hash列表校驗資料塊。下圖的第一行和第二行就組成了一個Hash List。

三、Merkle Tree(默克爾樹)

Merkle tree是由美國計算機學家merkle於1979年申請的專利,可以看做Hash List的泛化(Hash List可以看作一種特殊的Merkle Tree,即樹高為2的多叉Merkle Tree)。

在最底層,和雜湊列表一樣,我們把資料分成小的資料塊,有相應地雜湊和它對應。但是往上走,並不是直接去運算根雜湊,而是把相鄰的兩個雜湊合併成一個字串,然後運算這個字串的雜湊,這樣每兩個雜湊就結婚生子,得到了一個”子雜湊“。如果最底層的雜湊總數是單數,那到最後必然出現一個單身雜湊,這種情況就直接對它進行雜湊運算,所以也能得到它的子雜湊。於是往上推,依然是一樣的方式,可以得到數目更少的新一級雜湊,最終必然形成一棵倒掛的樹,到了樹根的這個位置,這一代就剩下一個根雜湊了,我們把它叫做 Merkle Root。

在p2p網路下載資料之前,先從可信的源獲得檔案的Merkle Tree樹根。一旦獲得了樹根,就可以從其他從不可信的源獲取Merkle tree。通過可信的樹根來檢查接受到的Merkle Tree。如果Merkle Tree是損壞的或者虛假的,就從其他源獲得另一個Merkle Tree,直到獲得一個與可信樹根匹配的Merkle Tree。

Merkle Tree和Hash List的主要區別是,可以直接下載並立即驗證Merkle Tree的一個分支。因為可以將檔案切分成小的資料塊,這樣如果有一塊資料損壞,僅僅重新下載這個資料塊就行了。如果檔案非常大,那麼Merkle tree和Hash list都很大,但是Merkle tree可以一次下載一個分支,然後立即驗證這個分支,如果分支驗證通過,就可以下載資料了。而Hash list只有等下載完整個hash list後才能驗證。

四、Merkle DAG(Merkle directed acyclic graph,默克爾有向無環圖)

Merkle DAG是ipfs開發團隊在Merkle tree的基礎上構建的,是ipfs中的一種資料結構。它跟Merkle tree很相似,但不完全一樣,比如:第一,Merkle DAG不需要進行樹的平衡操作,DAG可以存在單身節點;第二,非葉子節點允許包含資料,有時候小資料直接存在非葉子節點上。

DAG的格式如下:

type IPFSLink struct {
  Name string             // link 的名字
  Hash Multihash        // 資料的加密雜湊
  Size int                    // 資料大小
}

type IPFSObject struct {
  links []IPFSLink             // link陣列
  data []byte        // 資料內容
}

這樣的話,允許開發者可以完全控制物件的資料欄位,也就是說應用可以隨意定義自己的data型別和結構,理論上來說,任何一種資料結構都是可以的,比如我們的以太坊等其他公鏈資料,此處非常具有想象空間。。。