在研究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.
网友评论