在研究Filecoin的邏輯之前,IPFS作為其存儲實現的協議,其關鍵特性需要有初步的認識。IPFS是在前人的基礎上,借鑒了bt下載,github工程管理,DHT,SFS等成熟的點對點系統之后,做出的協議上的改進和優化。每個IPFS節點都會使用本地存儲作為全網存儲的一部分,所有節點都是平等的,沒有節點享有特權。節點與節點之間可以同步文件以及管理信息,他是一個獨立的,有許多子系統組成的系統。我們將把他拆分成不同的子模塊來分析,但是這并不意味著子模塊是獨立存在的,它們之間需要相互配合才能實現IPFS的各種能力。
1,IPFS節點標識
每一個ipfs節點都有一個唯一ID。首先通過S/Kademlia's
static crypto
puzzle方法生成一個密鑰對,然后對公鑰進行hash計算,得到一個hash值,此hash值就是該節點的唯一ID。每個新節點都會存儲節點的ID,公鑰和秘鑰。IPFS可以每次啟動都創建一個新節點,但是推薦使用舊的節點ID。Go語言版本的ID生成代碼:
difficulty =
n = Node{}
do {
n.PubKey, n.PrivKey = PKI.genKeyPair()
n.NodeId = hash(n.PubKey)
p = count_preceding_zero_bits(hash(n.NodeId))
} while (p < difficulty)
節點與節點建立連接之后,首先互相交換彼此的公鑰,并通過計算公鑰的hash,然后對比節點唯一ID與此hash值是否一致,作為判斷對方是否是一個有效的IPFS節點條件之一。
為了方便升級,IPFS節點在描述節點的hash值的同時,會在hash值前面增加hash生成的算法和hash值的長度,這種自描述的hash值使得節點與節點之間交互時,變得靈活和容易兼容。
2. 點對點網絡鏈接協議
a,IPFS支持各種傳輸層協議,他并不依賴于IP地址。
b,可靠性,如果底層網絡無法提供可靠性,ipfs使用utp和sctp協議來自己保證網絡的可靠性
c,可聯通性,ipfs支持NAT穿墻技術
d,數據完整性,ipfs可以進行檢查數據的hash以確定得到的數據是否是無損的
e,通過檢查消息發送者的公鑰,確保數據的所有權
3. 路由:文件位置定位
通過DSHT技術,IPFS可以定位其他節點的網絡地址以及能夠提供某數據塊的網絡節點信息。對于小于1KB的數據,IPFS直接存儲在DHT中,對于較大數據,IPFS將能夠提供特定數據的節點的NodeID存儲在DHT中。不同的場景下會有不同的技術實現,只要實現路由的基本接口,系統的其它模塊就可以正常運行,并不依賴于接口的具體實現。抽象的路由接口為:
type IPFSRouting interface {
FindPeer(node NodeId)
// gets a particular peer's network address
SetValue(key []bytes, value []bytes)
// stores a small metadata value in DHT
GetValue(key []bytes)
// retrieves small metadata value from DHT
ProvideValue(key Multihash)
// announces this node can serve a large value
FindValuePeers(key Multihash, min int)
// gets a number of peers serving a large value
}
4. 數據查詢與下載: BitSwap Protocol
BitSwap
Protocol的數據交換類似于BitTorrent下載,不同之處是,BitSwap
Protocol不拘泥于一個種子內關聯的數據塊,BitSwap
更像是一個存儲市場,任何節點都可以獲取數據塊,不管數據之間是否強相關或者什么樣的文件格式.節點與節點之間可以在這個市場交易數據塊
節點之間對數據交互需求,天然的引申出token這樣的價值代幣,來提現數據的存儲與輸入輸出,在這個過程中,如果對端節點訪問某個數據塊,但是自己并沒有存有這樣的節點時,自己應該發起一個有限級較低的服務,來幫助自己的朋友節點來尋找他需要的數據庫并幫其緩存。
A, BitSwap Credit
該協議鼓勵節點做種子,以方便別人再使用時可以快速找到想要的數據,節點默認可以隨意發送數據給其他節點,但是前提是對端沒有過度濫用這個機制,因此:首先節點統計他與其他節點之間的傳輸數據多少,如果對方收到數據多,分享的數據少,那么本節點可以根據這個比例來確定分享給對方節點的數據比例。如果對方節點共享的數據過少,那么本方節點可以決定停止共享數據給對方節點,過一定時間之后再共享數據。
B, BitSwap Strategy
傳輸策略有很多種,各有利弊,目前IPFS的策略正在開發中,但是有幾個總的原則需要滿足:
1,策略可以使得存儲交易的性能最優化
2,防止揩油的節點使得全網的性能下降
3,對陌生的或者惡意的節點有抵抗性
4,對信任的節點具有較高的性能
目前在實際中使用的策略模型為:
這個模型可以防止女巫攻擊,保護好與以前成功發生過數據傳輸節點的關系,并且能夠快速阻止變質的節點,直到它回復為止。
C,BitSwap Ledger
節點通過一個賬本數據結構記錄與其它節點之間的數據交換情況,每次點對點數據鏈接建立之后,首先會檢查賬本信息,如果賬本信息不一致,則重新開始記賬,這樣可能會導致攻擊者故意用錯誤的賬本來摸出自己的不良記錄,但是同時他也失去了其他節點對他的信任。是否允許經常丟棄賬本的節點接收數據取決于節點自身的安全設計,這個沒有嚴格的限制。同時節點也可以隨意丟棄關于某些節點的賬本信息,因為有些節點可能已經永遠消失了。賬本條目數據結構:
type Ledger struct {
owner NodeId
partner NodeId
bytes_sent int
bytes_recv int
timestamp Timestamp
}
D, BitSwap Specification
// Additional state kept
type BitSwap struct {
ledgers map[NodeId]Ledger
// Ledgers known to this node, inc inactive
active map[NodeId]Peer
// currently open connections to other nodes
need_list []Multihash
// checksums of blocks this node needs
have_list []Multihash
// checksums of blocks this node has
}
type Peer struct {
nodeid NodeId
ledger Ledger
// Ledger between the node and this peer
last_seen Timestamp
// timestamp of last received message
want_list []Multihash
// checksums of all blocks wanted by peer
// includes blocks wanted by peer's peers
// Protocol interface:
interface Peer {
open (nodeid :NodeId, ledger :Ledger);
send_want_list (want_list :WantList);
send_block (block :Block) -> (complete :Bool);
close (final :Bool);
}
Peer.open(NodeId, Ledger).
與對端建立連接的時候,節點會讀取存儲在本地的賬本信息,如果沒有則新建一個賬本,然后發送open消息給對端節點。對端節點收到open請求之后,根據本節點的賬本信息決定是否接受此請求并建立連接,如果本節點不被接受,則會提示合適的錯誤信息,如果接受節點的open請求,則對端節點檢查本地賬本與本節點的賬本記錄,如果一直則直接建立連接,如果不一致則新建關于本節點的賬本數據,然后建立連接。
Peer.send_want_list(WantList).
當鏈接建立之后,本節點會根據特定策略廣播want_list列表給所有對端節點,當對端節點收到want_list的廣播消息之后,會檢查本地存儲的數據塊,然后根據前面講到的策略發送數據給本節點。
Peer.send_block(Block).
發送數據動作比較直接,對端收到數據之后檢查hash值,然后返回檢查結果。如果成功接收數據,對端節點把數據庫從need_list
遷移到
need_list,同時本節點和對端節點同時更新數據傳輸賬本。如果傳輸失敗,對端接收節點可以根據情況,自行決定是否繼續接收后續的數據傳輸。
Peer.close(Bool).
關閉連接的參數說明對端是主動關閉連接還是超時關閉連接,連接關閉后,雙發情況關于該鏈接的所有數據,并保存好數據傳輸的賬本信息,供下次使用。
5. 數據存儲格式
DHT和BitSwap使得IPFS組件了點對點的數據塊存儲和分片系統,在此基礎上IPFS創建了Merckle
DAG數據結構,這樣所有的數據以及數據的鏈接可以通過hash唯一標示,同時可以根據hash值檢查數據是否無損,而且相同的hash對應相同的內容,通過hash值可以檢查重復的數據存儲。
type IPFSLink struct {
Name string// name or alias of this link
Hash Multihash // cryptographic hash of target
Size int // total size of target
}
type IPFSObject struct {
links []IPFSLink // array of links
data []byte // opaque content data
}
以上數據結構設計使得IPFS既可以根據內容尋址,又可以將數據的格式完全交給用戶自定義實現。IPFS對象可以通過多級目錄的方式訪問,類似Unix的文件系統。IPFS每個節點都會存儲有自己的本地存儲,本地節點訪問其它節點數據后會緩存數據內容,至少是暫時緩存。如果你希望某些數據對象長期保持在本地存儲,可以pin一下這個IPFS對象,這樣每次訪問次對象時都可以在本地存儲獲取。任何人都可以添加IPFS對象到全球網絡并針對對象加密,加密后的對象與未加密對象擁有不同的hash值,即使他們解密后擁有同樣的內容,再IPFS的管理里面他們屬于不同的對象,IPFS會根據用戶的私鑰對加密數據解密,加密屬性具有遞歸性,父對象加密的時候,子節點也需要解密才能訪問,當然父對象和子對象可以采用不同的秘鑰。加密對象的數據結構:
type EncryptedObject struct {
Object []bytes
// raw object data encrypted
Tag []bytes
// optional tag for encryption groups
}
type SignedObject struct {
Object []bytes
// raw object data signed
Signature []bytes
// hmac signature
PublicKey []multihash
// multihash identifying key
}
6. 文件系統
IPFS提供了具有版本管理能力的文件系統,IPFS把文件對象分成了4類:
A,文件對象:Blob,可尋址的二進制對象,類似操作系統里面文件系統存儲的數據塊。
{
"data": "some data here",
// blobs have no links
}
B,文件對象: list。List表示了一個有多個Blob組成的大型文件,在數據的開頭描述了該list的數據項的數據類型。
{
"data": ["blob", "list", "blob"],
// lists have an array of object types as data
"links": [
{ "hash": "XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x",
"size": 189458 },
{ "hash": "XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5",
"size": 19441 },
{ "hash": "XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z",
"size": 5286 }
// lists have no names in links
]
}
C,文件對象:tree 與list相比增加了name屬性
{
"data": ["blob", "list", "blob"],
// trees have an array of object types as data
"links": [
{ "hash": "XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x",
"name": "less", "size": 189458 },
{ "hash": "XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5",
"name": "script", "size": 19441 },
{ "hash": "XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z",
"name": "template", "size": 5286 }
// trees do have names
]
}
D,文件對象: commit,代表了任何對象在版本管理歷史中的一個快照
ipfs file-cat --json
{
"data": {
"type": "tree",
"date": "2014-09-20 12:44:06Z",
"message": "This is a commit message."
}, "links": [
{ "hash": "",
"name": "parent", "size": 25309 },
{ "hash": "",
"name": "object", "size": 5198 },
{ "hash": "",
"name": "author", "size": 109 }
] }
7. 命名系統
IPFS提供了IPNS技術使得用戶可以將不變的命名空間指向不同的數據內容。同時IPFS支持IPNS下的域名訪問,修改本機的DNS 文件,可以將較長的hash值訪問對象改為域名訪問:
# this DNS TXT record
ipfs.benet.ai. TXT "ipfs=XLF2ipQ4jD3U ..."
# behaves as symlink
ln -s /ipns/XLF2ipQ4jD3U /ipns/fs.benet.ai
# User can get a link from
/ipns/shorten.er/foobar
# To her own namespace
/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm
8. IPFS的適用場景
IPFS是由很多小的系統組成,模塊與模塊之間分工明確,可以靈活組合使用,實現不同場景下的多種功能:
As a mounted global filesystem, under /ipfs and /ipns. 2. As a mounted personal sync folder that automatically
versions, publishes, and backs up any writes.
3. As an encrypted file or data sharing system.
4. As a versioned package manager for all software.
5. As the root filesystem of a Virtual Machine.
6. As the boot filesystem of a VM (under a hypervisor).
7.
As a database: applications can write directly to the Merkle DAG data
model and get all the versioning, caching, and distribution IPFS
provides.
8. As a linked (and encrypted) communications platform.
9. As an integrity checked CDN for large files (without SSL).
10. As an encrypted CDN.
11. On webpages, as a web CDN.
12. As a new Permanent Web where links do not die.