1. 目标
-
熟悉IPFS概念
-
熟悉IPFS上传文件、下载文件过程
2. 概念
2.1 BACKGROUND
2.1.1 Distributed Hash Tables(DHTs)
-
Kademlia DHT
优点
- 【通信性能】通过大规模网络高效查找:查询平均需要通信向上取整节点。(例如,一个由10,000,000个节点组成的网络需要20个跳数)
- 【通信性能】低协调开销:优化了发送给其他节点的控制消息的数量
- 【安全】通过选择长期存在的节点来抵抗各种攻击
- 【应用】在对等应用程序中广泛使用,包括Gnutella和BitTorrent,形成了超过2000万个节点的网络。
-
Coral DSHT
优点
- 【通信性能】Kademlia将值存储在id与键最接近(使用XOR-distance)的节点中。这并不考虑应用程序数据的局域性,忽略可能已经拥有数据的远节点,并不管最近节点是否需要这份数据而去强制它们存储数据。这浪费了大量的存储和带宽。相反,Coral在能够提供数据块的对等节点存储地址信息
- 【通信性能】Coral将DHT API从get_value(key)放宽为get_any_values(key) (DSHT中的“sloppy”)。这仍然工作直到Coral用户只需要一个(工作)peer,而不是完整的列表。作为交换,Coral只能将值的子集分发到最近的节点,从而避免了热点(当一个键变得流行时,会重载所有最近的节点)
- 【通信性能】Coral根据区域和大小组织了一个称为簇的独立DSHT层次结构。这使得节点可以首先查询其区域内的对等节点,在不查询远处节点的情况下查找附近的数据,大大减少了查找的延迟
-
S/Kademlia DHT
S/Kademlia扩展了Kademlia以两种特别重要的方式来抵御恶意攻击:
- 【安全】S/Kademlia提供了安全的NodeId生成方案,并防止女巫攻击。它要求节点创建一个PKI密钥对,从密钥对中获得自己的身份,并对彼此的消息进行签名。一种方案包括一个工作证明加密谜题,以使生成女巫攻击的成本很高
- 【安全】S/Kademlia节点在不相交的路径上查找值,以确保在网络中存在大量对手的情况下,诚实的节点可以相互连接。即使对抗分数高达一半的节点S/Kademlia实现了0.85的成功率,
2.1.2 Block Exchanges - BitTorrentc
BitTorrent(简称BT)是一个文件分发协议,每个下载者在下载的同时不断向其他下载者上传已下载的数据。
BitTorrent是一个广泛成功的点对点文件处理系统,它成功地协调了互不信任的点(群)网络,在相互分发文件的过程中进行合作。BitTorrent及其生态系统中IPFS设计的关键特性包括:
- BitTorrent的数据交换协议使用了一种类似于tit-for-tat的策略,奖励那些相互贡献的节点,惩罚那些只窃取别人资源的节点
- BitTorrent同行跟踪文件片段的可用性,优先发送最罕见的片段。这减轻了种子的负担,使非种子同伴能够相互交易
- BitTorrent标准的tit-for-tat易受某些利用带宽共享策略的攻击。PropShare是一种不同的对等带宽分配策略,它能更好地抵抗利用策略,并提高群的性能
2.1.3 Version Control Systems - Git
版本控制系统提供了对随时间变化的文件建模的工具,并有效地分发不同的版本。流行的版本控制系统Git提供了一个功能强大的Merkle dag对象模型,它以分布式友好的方式捕获对文件系统树的更改。
- 不可变对象代表Files (blob)、Directories (tree)和Changes (commit)
- 对象是内容寻址的,通过其内容的加密散列
- 与其他物体的链接被嵌入,形成一个默克尔DAG。这提供了许多有用的完整性和工作流属性
- 大多数版本化元数据(分支、标签等)都是简单的指针引用,因此创建和更新的成本很低
- 版本更改仅更新引用或添加对象
- 将版本更改分发给其他用户只是简单地传输对象和更新远程引用
2.1.4 Self-Certified Filesystems - SFS
SFS[12,11]提出了两种引人注目的实现:
- 分布式信任链
- 平等共享的全局命名空间
SFS引入了一种用于构建自认证文件系统的技术:
使用以下scheme:
/sfs/<Location>:<HostID>
其中Location是服务器的网络地址,并且:HostID = hash(public_key || Location)
因此SFS文件系统的名称证明了它的服务器。用户可以验证服务器提供的公钥,协商共享密钥,并确保所有流量的安全。所有SFS实例共享一个全局命名空间,其中的名称分配是加密的,不受任何集中主体的限制。
2.2 IPFS DESIGN
IPFS协议被划分为负责不同功能的子协议堆栈
2.2.1 身份——管理节点身份的生成和更新
节点由一个NodeId标识,这是一个公钥的加密哈希,是用S/Kademlia的静态加密谜题创建的。节点存储它们的公钥和私钥(使用密码短语加密)。用户可以在每次启动时自由实例化一个新的节点标识,尽管这样会损失已积累的网络利益。节点被激励保持不变
2.2.2 网络——管理与其他对等体的连接,使用各种底层网络协议。可配置的
IPFS网络栈特性:
- 传输:IPFS可以使用任何传输协议,最适合于WebRTC数据通道(用于浏览器连接)或uTP(LEDBAT)
- 可靠性:如果底层网络不提供,IPFS可以使用uTP (LEDBAT[14])或SCTP[15]提供可靠性
- 连通性:IPFS也使用ICE NAT穿越技术
- 完整性:可选地使用哈希校验和检查消息的完整性
- 真实性:可选地检查mes- sage的真实性,通过使用发送方的特权密钥进行数字签名。
2.2.3 路由——维护定位特定对等体和对象的信息。响应本地和远程查询。默认为DHT,但可切换
IPFS节点需要一个路由系统,它可以找到其他节点的网络地址,以及可以为特定对象服务的节点。IPFS使用S/Kademlia和Coral DSHT实现这一点。IPFS的对象大小和使用模式类似于Coral和Mainline,因此IPFS DHT根据其大小对存储的值进行区分。小值(等于或小于1KB)直接存储在DHT上。对于较大的值,DHT存储引用,这些引用是可以为块提供服务的节点的nodeid
2.2.4 块交换——一个新的块交换协议(BitSwap),它管理有效的块分配。以市场为模型,对数据复制的激励很弱。可切换的贸易策略
在IPFS中,数据分发是通过使用BitTorrent启发的协议BitSwap与对等点交换块来实现的。像BitTorrent一样,BitSwap对等体正在寻找一组块(want_list),并有另一组块交换(have_list)。与BitTorrent不同,BitSwap并不局限于一个torrent中的区块。BitSwap操作是一个持久的市场,节点可以获取他们需要的块,而不管这些块是什么文件的一部分。这些块可以来自文件系统中完全不相关的文件。节点聚集在一起进行交易。
2.2.5 对象——一个Merkle DAG,由具有链接的内容定位的不可变对象组成。用于表示任意的数据结构,例如文件层次结构和通信系统
DHT和BitSwap允许IPFS形成一个大规模的点对点系统,用于快速、可靠地存储和分发块。在这些之上,IPFS构建了一个Merkle DAG,一个有向无环图,其中对象之间的链接是嵌入源中的目标的加密散列。这是Git数据结构的一般化。
默克尔DAG为IPFS提供了许多有用的属性:
- 内容寻址:所有内容由其多哈希校验和唯一标识,包括链接
- 抗篡改:所有内容都通过校验和进行验证。如果数据被篡改或损坏,IPFS会检测到它
- 重复数据删除:所有包含相同内容的对象都是相同的,且只存储一次。对于索引对象,如git树和提交,或数据的公共部分,这尤其有用。
2.2.6 文件——受Git启发的文件版本的文件系统层次结构
IPFS还定义了一组对象,用于在Merkle DAG之上对版本化的文件系统建模。该对象模型类似于Git s:
- 块:一个可变大小的数据块
- 列表:块或其他列表的集合
- 树:块、列表或其他树的集合
- 提交:树版本历史中的快照。
2.2.7 命名——一个自认证的可变名称系统
到目前为止,IPFS堆栈形成了一个点对点块交换,构造了一个对象的内容寻址DAG。它用于发布和检索不可变对象。它甚至可以跟踪这些对象的版本历史。但是,缺少一个关键组件:可变命名。没有它,所有新内容的通信都必须在带外进行,发送IPFS链接。需要的是在同一路径上检索可变状态的某种方法。值得说明的是,如果可变数据是必要的,我们最终努力建立一个不可变的默克尔DAG。考虑一下来自Merkle DAG的IPFS属性:对象可以(a)通过其散列检索,(b)完整性检查,©链接到其他对象,以及(d)无限期缓存。在某种意义上:对象是永久的。这些是高性能分布式系统的关键属性,在分布式系统中,数据跨网络链路移动的代价很高。对象内容寻址构建了一个具有(a)显著带宽优化、(b)不可信内容服务、©永久链接和(d)对任何对象及其引用进行完全永久备份的能力的web。Merkle DAG(不可变的内容寻址对象)和命名(指向Merkle DAG的可变指针)瞬时出现在许多成功的分布式系统中。这包括Git版本控制系统,它有不可变对象和可变引用;和Plan, UNIX的分布式继承者,及其可变的Fossil和不可变的Venti文件系统。LBFS也使用可变索引和不可变块。
2.3 IPFS共识
IPFS创新的采用了一种混合共识机制——复制证明(PoRep)+时空证明(PoSt)+ 预期共识(EC)
- 复制证明:共识机制中的核心因素,尽管IPFS的网络协议、共识、其他算法都基本定型,但是复制证明仍然处于不断完善的方案中。
- 时空证明:(PoSt)提出了证明链(proof-chain)的数据结构,证明链把一些的挑战(challenge)和证明(proof)链接起来形成。在证明链的基础上添加上时间段,这样就得到了一段时间内的矿工存储数据的证明,这就是时空证明(Proof of Spacetime,PoSt)。PoSt可以证明在该段时间内矿工存储了特定的数据,并且利用时间戳锚定这些证明链,这样即使验证者(verifier)不在线,也可以在未来的某个时间内利用时空证明去验证该矿工生成了证明链,PoSt会被提交到链上用来产生新的Block。
- 预期共识:(Expected Consensus,EC)是在每一轮里面选举出来一名或者多名矿工来创建新的区块,矿工赢得选举的可能性跟矿工当前的有效存储(算力)成正比。IPFS把矿工在网络中的当前存储数据相对于整个网络的存储比例转化为矿工投票权(voting power of the miner)。无论在该周期里,选举出来的是一名还是多名矿工,被选举出来的矿工都需要创建新的区块,并把新的区块对网络进行广播。 尽管链中的区块是线性的,但是IPFS的区块数据结构采用的DAG(有向无环图),可以在同一时间产生多个区块(所以Filecoin的交易要比BTC的有效的多,这也是为什么把Filecoin叫做“可能的blockchain 3.0”的原因)
Filecoin首创的混合共识机制,从根本上定义了Filecoin是一个合理高效、去中心化的系统,并体现出Filecoin的公平性、保密性和公开可验证性
3. 上传文件

3.1 生成默克尔DAG的结构
生成的结构有两种Layout:balanced和trickle的。这里介绍默认的balanced结构,首先生成root作为根节点,然后将文件分割,默认按照256KB大小读取一个chunk,生成叶子节点,依次生成node1,node2,root节点会有Link指向挂在root节点的叶子节点node1和node2。root节点下面能够Link的叶子节点数量是有限的,IPFS中默认设置的是174个(定义的Link的总的大小是8KB,每个Link的大小是34 + 8 + 5【sha256 multihash + size + no name + protobuf framing】,默认的Link的个数为8192/47约等于174)。

如下图所示,超过174个后则会新创建一个new root节点,并Link到old root,新的chunk作为node3(这里用node3简约了,实际上是第175个节点)被new root直接Link。

当继续有新的chunk添加时,则会生成node34作为node3和node4的父节点,node34含有两个Link分别链接到node3和node4。

IPFS在init的时候会生成.ipfs目录,如下图所示,其中blocks则为文件块存储的目录,datastore为leveldb数据库,其中存储了文件系统的根哈希等,存储相关的配置关联在.ipfs目录下面的config文件。

3.2 对块进行存储
- 如下图所示,一个Block存储时,首先由dagService(实现了DAGService接口)调用Add进行添加;
- 之后由blockService(实现了BlockService接口)调用AddBlock添加该Block;
- 再调用arccache的Put,arccache是对存储的Block做arc策略的缓存;
- 再之后由VerifBS调用Put进行存储,VerifyBS主要对CID的合法性进行校验,合法则进行Put;
- 接着blockstore(实现了Blockstore接口)调用Put进行存储,Put函数中会对CID进行转化,调用dshelp的CidToDsKey方法将CID转化成存储的Key;
- 再接着调用keytransform.Datastore的Put,Put函数中会将前缀拼上,这时Key加上了前缀/blocks;
- 然后调用measure的Put函数,measure是对mount的封装;
- 之后调用mount的Put函数,mount和IPFS的config配置文件中结构对应,根据key去查找对应的datastore,由于前缀是/blocks则可以找到对应的measure;
- 调用该measure的Put函数;
- 最后调用flatfs的Put函数,由Put函数调用doPut最终调用encode函数将完整的block写入的目录指定为/home/test/.ipfs/blocks/WD,其中WD来自于blocks/CIQFSQATUBIEIFDECKTNGHOKPOEE7WUPM5NNNSJCCDROMM6YHEKTWDY中的倒数第三第二个字符。这样该Block则写入了该目录下面的文件中。


4. 下载文件

- 检查本地的blockstore中是否存在请求的数据,如果存在则直接从本地返回;否则会向对等节点发送block hash列表;
- 对等节点通过DHT和路由层算法,找到每个block hash所在的节点,将文件返回来;
- 本地节点在接收block文件的同时缓存一份到本地的blockstore中
- 更新DHT
- 组装block文件,返回至用户端