IPFS 基本原理 - killelder/cryptocurrency GitHub Wiki

IPFS包含了許多互聯網技術的綜合體, 包含了p2p, DHTs, Git, Bittorrent等等
IPFS裡面包含了幾個項目: IPFS, Filecoin, libp2p, IPLD, Multiformats
IPFS : 應用數據
Filecoin : 價值數據, 激勵礦工儲存
libp2p : 傳遞數據, 網路交換協議
IPLD : 定義數據, 命名, 對象, 文件
Kademlia DHT
libp2p協議
IPLD(Inter Planetary Linked Data)協議

Hash ID

HostID = hash(public_key || Location)

Bootstrap

因為IPFS是基於DHT技術, 所以網路裏面沒有tracker, 一個新加入的節點要如何加入網路呢?
新加入的節點會透過一個已經在網路上的節點地址, 這樣就可以加入網路了
所以ipfs 提供了bootstrap來完成這個工作

IPFS IPLD Objects(IPFS 對象)

IPFS本質上是一個用於檢索和共享IPFS對象的P2P系統, 一個IPFS對象是一個具有兩個字段的數據結構
Data : 小於256kB的非結構化數據塊(blob)
Links : 一個Link結構體的數組, 指向其他IPFS對象

Link結構有三個數據字段
Name : Link的名字
Hash : Link的Hash
Size : Link指向對象的大小

IPFS對象通常採用Base58編碼的散列引用,

> ipfs object get QmarHSr9aSNaPSR6G9KFPbuLV9aEqJfTk1y9B8pdwqK4Rq

{
    “Links”: 
    [{
        “Name”:“AnotherName”,
        “Hash”:“QmVtYjNij3KeyGmcgg7yVXWskLaBtov3UYL9pgcGK3MCWu”,
        “Size”: 18},
    },

    {
        “Name”:“SomeName”,
        “Hash”:“QmbUSy8HCn8J4TMDRRdxCbK2uCCtkQyZtY6XYv3y7kLgDC”,
        “Size”: 58
    }],
    “Data”: “Hello World!”
}

實際去IPFS操作可以看到所有的散列都是以"Qm"開頭的, 因為IPFS用的是一個multihash的格式
前兩個字節用來指定Hash function和Hash長度
Qm ==> 0x1220 其中0x12代表SHA256, 0x20代表32Byte長度

數據和命名鏈結構成的IPFS對象的集合就是Merkle DAG結構

FileSystem

一個<=256kB的文件

data代表該文件的內容(還需要在文件數據的開始和結尾處還要分別附加一小段header和footer數據), data 不包含Links, 不包含name

{“Links”: [],

“Data”: “\u0008\u0002\u0012\rHelloWorld!\n\u0018\r”}

>256kB的大文件

是由一個鏈結列表來表示的, 其中裡面鏈結到的小文件塊Name都是空的

{“Links”: [{

    “Name”: “”,
    “Hash”: “QmYSK2JyM3RyDyB52caZCTKFR3HKniEcMnNJYdk8DQ6KKB”,
    “Size”: 262158},

    {“Name”: “”,
    “Hash”: “QmQeUqdjFmaxuJewStqCLUoKrR9khqb4Edw9TfRQQdfWz3”,
    “Size”: 262158},

    {“Name”: “”,
    “Hash”: “Qma98bk1hjiRZDTmYmfiUXDj8hXXt7uGA5roU5mfUb3sVG”,
    “Size”: 178947}],

    “Data”: “\u0008\u0002\u0018*\u0010 \u0010 \n”
}

Directory(目錄)

目錄由指向表示文件或其他目錄的IPFS對象的Link列表來表示, 鏈結的name是文件和目錄的名稱

{“Links”: [
    {“Name”: “test”},
    {“Name”: “helloworld”},
}

版本化文件系統(Versioned File Systems)

IPFS可以表示Git所使用的數據結構, 以支持版本化的文件系統
對於IPFS修改檔案後, 會完全存成另外一個新的檔案, 舊的還會留著
而且如果有兩個完全相同的檔案, 也會自動去重複(不會重複儲存兩個一樣內容的檔案)

區塊鏈(Blockchain)

區塊鏈天然的擁有一個DAG結構, 後續塊是通過前旭塊的hash值與它們相連接
這與IPFS結構相似

當我們加了一個檔案到IPFS會發生甚麼事

首先我們會把data透過Hash變成CID

data(any format) -> 10010....(Raw) -> fab13djal(Digest) -> QmcBaE7V(CID)

透過CID我們可以找到檔案
但沒有這麼簡單...... 萬一我們將來想改變內容怎麼辦, 如果有人發明了更好的Hash function怎麼辦, 或是IP系統要升級怎麼辦
所以IPFS開發人員想到了這一點

Multihashing

這個hash的Qm就代表了本身用了甚麼hash function
(上面有解釋Qm)
然而為什麼Qm是1220
這是由base58 encode來的, base58拿掉了0,o,O,I,i,l,+,/這些會讓人混淆的字

Merkle DAG -> IPLD

Merkle DAG <-> IPLD <-> data structure
IPFS裡面很多其實都是在講同樣東西的, 但是總是被不同名詞給搞混
例如這裡要說的Merkle DAG, 其實就是在講IPFS 的data structure

利用這樣的結構有幾個好用的屬性 :

  1. 內容尋址 : 所有的內容和鏈結都由hash當作標示
  2. 防竄改 : 如果數據被竄改, hash會馬上發現
  3. 重複數據刪除 : 一樣的hash不會多存
    ipfs obj圖示化

當我們下object get的時候

ipfs object get /ipfs/QmdcYvbv8FSBfbq1VVSfbjLokVaBYRLKHShpnXu3crd3Gm

{  
  "Links":[  
    {  
      "Name":"bar",
      "Hash":"QmeBpzHngbHes9hoPjfDCmpNHGztkmZFRX4Yp9ftKcXZDN",
      "Size":61
    },
    {  
      "Name":"baz",
      "Hash":"QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR",
      "Size":12
    }
  ],
  "Data":"\u0008\u0001"
}

若當我們下dag get的時候

ipfs dag get QmdcYvbv8FSBfbq1VVSfbjLokVaBYRLKHShpnXu3crd3Gm

{  
  "data":"CAE=",
  "links":[  
    {  
      "Cid":{  
        "/":"QmeBpzHngbHes9hoPjfDCmpNHGztkmZFRX4Yp9ftKcXZDN"
      },
      "Name":"bar",
      "Size":61
    },
    {  
      "Cid":{  
        "/":"QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR"
      },
      "Name":"baz",
      "Size":12
    }
  ]
}

可以看出是差不多的, 但以後可能都會使用ipfs dag替代ipfs object
Cid是一個新的概念(不太確定有甚麼新的概念), 但聽說是可以為了升級之類的
IPFS CID

File層

看來不只是我這麼想, File層原本定義blob, list, tree, commit
原本希望把Git版本控制等等的東西放上去
但是看起來整體資料結構跟Object層沒差
另外一個部落客跟我有一樣的想法
他認為File層已經被遺棄掉
姑且就讓我們相信吧

疑惑的地方

突然看到網路上有人問說, 假設我現在有一個directory, 裡面有一個檔案
然後我改變裡面的檔案內容, 此時裡面檔案的hash值會變化
然而directory的值應該會跟著變化, 這樣整個directory的hash值應該也會跟著變化??
下面只要有一個變化, 上面的hash不是會全部變化嗎??
從IPFS Tutorials上面看來,
也就是沒有修改檔案的概念, 只有上傳新檔案的概念
(只有ipfs add)
上傳後的檔案, 全部都丟在/ipfs的根目錄下
IPFS上面只能用Hash值去連接到檔案

而IPNS才有檔名這種概念
因為網站不能一更新別人就找不到, 所以利用自己的節點ID不變這個特性當成入口
每個人都有唯一的節點id, 通過重新指向這個節點id的Hash值
example:

QmAAAAA 是你的id, 原本的網站是 QmBBBBB  
QmAAAAA -> QmBBBBB  
然後你更新了網站, 網站變成 QmCCCCC  
這時只要重新把QmAAAAA 定址到 QmCCCCC就可以  
別人每次連線還是都連到你的QmAAAAA  
但就可以指向不同的位置, 去連結到更新後的網站  

P2P技術詳解
IPFS內部原理入門
IPFS Tutorials
IPFS-IPNS入門筆記
What’s really happening when you add a file to IPFS?
understanding the ipfs white paper-2
BitSwap

⚠️ **GitHub.com Fallback** ⚠️