LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 新闻观点 > IPFS白皮书(中文版)

IPFS白皮书(中文版)

2019-10-22 Online 来源:区块链网络
IPFS白皮书(中文版)

翻译者:张默默

摘要

星际文件系统(IPFS)是一个点对点分布式的文件系统,旨在寻找并连接所有具有相同文件系统的计算机设备。在某些方面,它有些类似Web系统,但IPFS更准确的讲,应该是一个通过Git仓库分布式存储的BitTorrent集群。换句话说,IPFS提供了一个高吞吐量的数据存储模块,其中数据都是带有地址的,通过超链接地址可以查询到存储的数据。这就构成了一个广义的Merkle GAG数据结构,基于它我们可以创建一个版本文件系统,或区块链,甚至一个永久存在的网页。IPFS结合了分布式哈希列表、去中心化的数据交换、自我认证的命名空间三个方面的技术。IPFS不存在单节点故障系统瘫痪的问题,节点之间也不需要相互信任。

1.简介

人们已经在全球分布式文件系统领域做了很多次尝试。有一些系统取得了重大的成功,但其余的却完全失败了。在学术尝试中,AFS取得了非常全面的成功,而且至今还在被应用。而其他的就没有获得一样的成功。除了学术之外,目前最成功的系统是面向大媒体文件(音频和视频)的点对点文件共享应用。最值得注意的是,?Napster,KaZaA?和BitTorrent[2]开发的大文件分发系统可支持1亿用户同时在线使用。即使在今天,BitTorrent依旧维持着每天千万个活跃节点的巨大部署。这些应用具有更多的用户和分发文件比那些学术文件系统的理论数据。然而,这些应用并不是作为建立基础架构而设计的。虽然已经成功地进行了调整,但是还达不到一个具有全球性、低延迟和去中心化分发的通用文件系统。

可能是因为对大多数用例来说,已经存在了一个足够好的系统:HTTP。到目前为止,HTTP是最成功的“分布式文件系统”。与浏览器一起使用,HTTP已经具有了巨大的科技和社会影响力。它已经成为互联文件传输最实际有效的方法。然而,它并没有好好利用最近15年发明的数十种非常优越的分布式文件技术。从一个方面考虑,由于后向兼容性数量的限制和对当前模型下需要大量的投入,继续发展改进Web基础框架是几乎不可能的。但从另一个方面考虑,自HTTP出现以来,已有一些新的网络协议出现,并得到广泛应用。但缺乏的就是设计升级:加强当前的HTTP Web,并引入新的功能且不降低用户的体验效果。

业界运用HTTP这么长时间,是因为传输一些小文件相对较便宜,甚至一些网络拥堵的小机构也是如此。但是我们正在进入一个数据分发的时代,且伴随着很多新的挑战:(a)托管和分发PB级数据集;(b)计算跨组织的超大数据;(c)大批量的高清晰度按需或实时媒体流;(d)大规模数据集的版本化和链接;(e)防止意外丢失重要文件等。其中很多可以归纳为“大量数据,随处可以访问”。受关键特性和带宽的影响,我们已经放弃了将HTTP作为不同文件分发协议。接下来让它们成为Web本身的一部分。

正交于高效数据分发和版本控制系统,已经设法开发重要的数据协作工作流程。Git,一个分布式源代码版本控制系统,开发了许多有用的方法来建模和实现分布式数据操作。Git工具链提供了灵活的版本控制功能,这正是大量的文件分发系统所严重缺乏的。由Git启发的新解决方案正在出现,如Camlistore [?],个人文件存储系统,Dat [?]数据协作工具链和数据集包管理器。Git已经影响了分布式文件系统设计[9],因为其内容涉及到Merkle DAG数据模型,能够实现强大的文件分发策略。还有待探讨的是,这种数据结构如何影响面向高吞吐量的文件系统的设计,以及如何升级Web本身。

本文将介绍IPFS,一种新颖的点对点版本控制文件系统,旨在协调这些问题。IPFS结合了过去那些成功系统的经验。以接口为重点的集成精心地产生的一个系统,其效果要比它的组成部分的总和要好的多。IPFS的原则是建模成一个所有数据拥有一个同样的Merkle DAG,同时作为Merkle DAG的一部分。

2.背景

本小节将回顾IPFS所结合的那些成功的点对点系统的重要特性。

2.1 分布式哈希表

分布式哈希表已经广泛应用于点对点系统元文件的协调和维护。

2.1.1 Kademlia DHT

Kademlia DHT是一种流行的DHT,它可以提供:1. 通过大量网络进行高效查询:平均查询(log2N)节点。 (例如,20跳10万个节点的网络)2. 低协调开销:优化发送到其他节点控制消息数量。3. 通过选择长期活跃节点来抵御多样的攻击。4. 在点对点应用程序中广泛使用,包括Gnutella和BitTorrent,形成了超过2000万个节点的网络[16]。

2.1.2 Coral DSHT

虽然一些点对点文件系统直接在DHT中存储数据块,这种“数据被强行存储在那些不需要这些数据的节点上,导致存储和带宽的浪费”[5]。Coral DSHT在三个特别重要的方式扩展了Kademlia:1. Kademlia将数值存储在那些序号离关键节点最近的(使用XOR距离)节点上。它并不将应用程序数据的位置考虑进来,而是无论它们需不需要,都会强制将数据存储在最近的节点上,而忽略那些可能已经存有该数据的相距远的节点。这将浪费了大量的存储空间和带宽。相反,Coral存储对等节点的地址,这些节点能够提供所需的数据块。2. Coral放宽了DHAT API的属性,将get_value(key)改成了get_any_values(key) (DSHT中的 “sloppy” )。只要Coral用户仅仅需要一个单(工作)节点,而不是完整的列表,那么这依然是有效的。作为回报,Coral可以仅将子集分配到“最近”的节点,避开热点(当密钥变得流行时,重载所有最近的节点)。3. 另外,Coral根据区域和大小组织了一个称为集群的独立DSHT层次结构。这使得节点首先查询其区域中的对等体,“查找附近的数据而不查询远程节点”[5]并大大减少查找的延迟。

2.1.3 S/Kademlia DHT

S/Kademlia[1]拓展了Kademlia,用以保护抵御恶意攻击,具体方法如下2种:1. S/Kademlia提供策略来保护节点序列号的生成,防止遭受女巫攻击。它要求节点生成自己的PKI私钥对,以便通过私钥对来确认它们的身份。并且互相之间对彼此的消息进行签名。有一个策略是包含一个POW加密的难题,使女巫攻击的成本非常昂贵。2. S/Kademlia节点通过不相交的路径查找值,目的是确保诚实节点在网络中出现大量敌手的情况下,彼此之间能够进行连接。S/Kademlia的成功率达到了0.85,甚至是在一半节点都是敌手的情况下。

2.2 块交换-BitTorrent

BitTorrent是一个非常成功的点对点文件分享系统,它成功的协调网络中互不信任的节点彼此合作,将文件数据片相互分发。BitTorrent和它的生态系统主要的特征启示了IPFS的设计,具体特此如下:1. BitTorrent的数据交换协议使用一种类似“针锋相对”的奖励策略,奖励互相贡献的节点,惩罚那些只汲取他人资源的节点。2. BitTorrent节点跟踪文件碎片的可用性,优先发送稀有的碎片。这减轻了种子节点的负担,同时使非种子节点也能够彼此进行交易。3. 对于一些剥削带宽共享策略,BitTorrent的标准tit-for-tat策略是非常脆弱的。然而,PropShare[8]是一种不同的对等带宽分配策略,可以更好的抵制剥削战略,提高集群的表现。

2.3 版本控制系统-Git

版本控制系统提供了通过时间对文件变化进行建模的设施,并有效地分发不同的版本。Git是最流行的版本控制系统,它提供了一个强大的默克尔DAG对象模型,该模型以分布式友好的方式捕获对文件系统树的更改。1. 通过不可变的对象表示文件(blob)、目录(tree)和更改(commit)2. 将它们的内容进行加密,得到哈希值。让该哈希值与对象有关联,实现其内容是可寻址的。3. 链接到其他对象是嵌入的,形成一个Merkle DAG。这提供了很多有用的完整体和工作流属性。4. 大部分情况下都是通过简单地指针引用来标定元文件版本信息(分支,标号等),因此创建和更新数据成本低廉。5. 版本的更改仅仅是更新引用或添加新的对象。6. 给其他用户分发版本变化的信息仅仅是通过简单地对象传输和远程引用的更新来实现。

2.4 自我认证文件系统-SFS

SFS[12,11]提出了两种编译实现方式,即(a)分布式信任链和(b)平等共享全球命名空间。SFS在创建自我认证文件系统中引进了一种新技术:运用以下策略实现处理远程文件系统:/sfs/<Location>:<HostID>其中Location是网络服务器地址,Host ID = hash(public_key||Location)。因此SFS文件系统的名字认证了它的服务。用户可以通过服务提供的公钥来验证,协商一个共享的私钥,保证所有的通信。所有的SFS实例都共享了一个全局的命名空间,这个命名空间的名称分配是加密的,不被任何中心化体控制。

3. IPFS 设计方案

IPFS是一个分布式文件系统,它结合了之前点对点系统的成功观点,包括DHTs、BitTorrent、Git、和SFS。IPFS的贡献在于简化和发展,还有将已经证明过的技术连接起来形成一个独立的衔接系统,该系统的效果要大于它组成部分的总和。IPFS提供了编写和部署应用程序的新平台,以及一个分发和大数据版本化的新系统。IPFS甚至可以改进网络本身。

IPFS是点对点系统,没有节点拥有特权。IPFS节点在本地存储IPFS对象。节点之间互相连接并传输对象。这些对象表现为文件和其它数据结构。IPFS协议可细分为一系列负责不同功能的子协议:1. 身份:管理节点的身份生成和验证。详见3.1部分。2. 网络:管理其它对等节点的连接,使用各种底层网络协议。可配置的。详见3.2部分。3. 路由:维护信息以定位具体的节点和对象。响应本地和远程查找。默认为DHT,但是可替换的。详见3.3部分。4. 交换:一种新的区块交换协议(BitSwap),负责管理有效区块的分发。模拟市场,弱激励数据复制。交易策略是可替换的。详见3.4部分。5. 对象:具有链接的内容寻址不可更改对象的Merkle DAG。用于表示任意数据结构,例如文件层级和通信系统。详见第3.5节6. 文件:受Git启发产生的版本文件系统层。详见3.6部分7. 命名:一个自我认证的可变命名系统。详见3.7部分。

这些子系统并不是独立的,他们集成在一起,并利用它们的混合特性达到杠杆的效应。然而,在从下到上构建协议栈中,分开描述它们是有用的。

*注释:下文中数据结构和函数用Go语言语法表示。

3.1 身份

节点由NodeId标识。通过S/Kademlia静态加密算法产生一个公钥,公钥进行加密哈希运算得到值就是NodeId。节点存储它们的公钥和私钥(用密码加密)。用户可以在每次启动时自由地设置一个“新”节点身份,尽管这会损失积累的网络利益。激励节点保持不变。

type?NodeId?Multihash?type?Multihash?[]byte//self-describing?crypto?graphic?hash?digest//自定义的哈希散列加密算法type?PublicKey?[]byte

3?纵观全文,hash和checksum指的是加密算法和数据的哈希值

type?PrivateKey?[]byte//self-describing?keys//自定义的私钥type?Node?struct?{NodeId?NodeID?PubKey?PublicKeyPriKey?PrivateKey}

基于S/Kademlia的IPFS身份生成:

difficulty?=<?integer?parameter?>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(other.PublicKey)等于other.NodeId。如果不相等,则连接被终止

关于加密函数的注意事项:IPFS不是将系统锁定到一组特定的函数选择,而是支持自我描述的值。哈希摘要值以多重哈希格式存储,其包括指定使用的哈希函数的头和以字节为单位的摘要长度。例如:<function code><digest length><digest bytes>

这就允许系统(a)为用例选择最佳函数(例如,更强的安全性或更快的性能),并且随着函数选择的变化而发展。自定义值允许使用不同的可相容的参数选择。

3.2 网络

IPFS节点在网络中与数以百计的其他节点进行有规律地通信,可能跨越广域网络。IPFS网络堆栈特性:? 传输层:IPFS可以使用任何传输协议,并且最适合WebRTC DataChannels [?](用于浏览器连接)或uTP(LEDBAT [14])。? 可靠性:如果底层网络不提供可靠性,IPFS可使用uTP(LEDBAT [14])或SCTP [15]来提供可靠性。? 可连接性:IPFS还可以使用ICE NAT穿墙打洞技术[13]。? 完整性:可以使用哈希校验和来检查消息的完整性。? 可验证性:可以使用发送者的公钥使用HMAC来检查消息的真实性。

3.2.1 对等节点寻址注意事项

IPFS可以使用任何网络; 它不依赖于IP或假设访问IP。这允许IPFS可用来覆盖网络。IPFS将地址存储为多层地址,这个多层地址是由字节字符串构成的,以便于给底层网络使用。多层地址提供了一种方式来表示地址及其协议,包括对封装的支持。例如:

#?an?SCTP/IPv4?connection/ip4/10.20.30.40/sctp/1234/#?an?SCTP/IPv4?connection?proxied?over?TCP/IPv4/ip4/5.6.7.8/tcp/5678/ip4/1.2.3.4/sctp/1234/

3.3 路由

IPFS节点需要一个路由系统,它可以找到:(a)其它节点的网络地址;(b)可以服务特定对象的对等节点。IPFS运用基于S/Kademlia和Coral的DSHT,利用在2.1部分讲到的特性,来实现路由系统的要求。在对象大小和使用类型方面, IPFS 类似于Coral[5] 和Mainline[16], 因此,IPFS DHT根据其大小对存储的值进行区分。小的值(等于或小于1KB)直接存储在DHT上。对于更大的值,DHT只存储值索引,这个索引就是一个可以提供区块的对等节点的NodeId。

DSHT接口类型,具体如下:

type?IPFSRouting?interface{ FindPeer?(node?NodeId)//gets?a?particular?peer’s?network?address?//获取特定NodeId的网络地址SetValue?(key[]bytes,?value?[]bytes)//stores?a?small?meta?data?value?in?DHT//往DHT存储一个小的元数据GetValue?(key[]bytes)//retrieves?small?meta?data?value?from?DHT//从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//?获取服务于该大数据的节点。}

注意:不同的用例将要求基本不同的路由系统(例如,广域网中使用DHT,局域网中使用静态HT)。因此,IPFS路由系统可以根据用户的需求进行替换。只要满足上边的接口,系统的其余部分就都能继续正常运行。

3.4 块交换 -BitSwap协议

在IPFS中,受BitSwap协议启发,对等节点利用BitTorrent通过交换数据区块实现数据的分发。和BitTorrent一样,在数据交换时,BitSwap节点不断获取一组数据区块(want_list),同时提供另一组数据区块(have_list)。不同于BitTorrent的是,BitSwap并不仅限于一个torrent中的数据区块。BitSwap可以当作一个永久的市场。在这个市场内,节点可以获取它们想要的数据区块,而不管那些块属于哪个文件的哪个部分。在文件系统中,这些块可能完完全全来自一些不相关的文件。节点们聚在一起,在市场上进行数据交换。

虽然数据交换系统的概念意味着可以创建虚拟货币,但这将需要一个全球账本来跟踪货币的所有权和转移。这可以作为实施BitSwap的策略,具体在以后的论文中探讨。

在基本情况下,BitSwap节点不得不以区块的形式相互提供直接值。当跨节点的块进行分发处于互补的时候,也就是彼此各取所需的时候,这才会工作的很好。通常情况下并非如此。在一些情况下,节点们必须为它们自己的块工作。假如一个节点并没有其它节点需求的任何数据(一点都没有),它会拥有比需求节点本身更低的优先级去寻求该数据。这会激励节点们去缓存和传播稀有的碎片,甚至它们根本对这些碎片没有直接的兴趣。

3.4.1 BITSWAP 信用

这个协议必须带有激励机制, 去激励节点去seed 其他节点所需要的块,而它们本身是不需要这些块的。 因此, BitSwap的节点很积极去给对端节点发送块,期待获得报酬。但必须防止水蛭攻击(空负载节点从不共享块),一个简单的类似信用的系统解决了这些问题:1. 对等节点间会追踪他们的平衡(通过字节认证的方式)。2. 随着债务增加而概率降低,对等者概率的向债务人发送块。注意的是,如果节点决定不发送到对等体,节点随后忽略对等体的ignore_cooldown超时。 这样可以防止发送者尝试多次发送(洪水攻击) (BitSwap默认是10秒)。

3.4.2 BitSwap策略

BitSwap对等节点可能采用不同的策略,这些策略对整个数据块的交换产生了截然不同的影响。在BitTorrent中,虽然明确规定了一个标准的策略(tit-for-tat),其他多样的策略也已经被实施,从BitTyrant [8](尽可能分享)到BitThief [8](利用一个漏洞,从不共享),再到PropShare [8](按比例分享)。BitSwap节点可以类似地实现一系列的策略(良好和恶意)。对于功能的选择,应该旨在:1. 最大化实现节点的交易和整体的交易。2. 防止空负载节点利用和减少交易3. 对于未知的策略,要保持有效的抵御性4. 对信任节点要保持宽容。

对于这样策略的开发将是未来的工作。在实践中,函数能起到作用的一个选择是一个S形,用负债比例来衡量:让负债比例r在一个节点和它对等节点之间:r = bytes_sent/(bytes_recv+1)根据r,发送到负债节点的概率为:P(send | r ) = 1 ? ( 1/ ( 1 + exp(6 ? 3r) ) )正如你看到的下图,当节点负债比例超过节点已建立信贷的两倍时,函数值会急速下降。

负债比率作为信任的衡量标准:对于之前成功的互换过很多数据的节点会宽容对等债务,而对不信任或不了解的节点会严格很多。这样以来会抵御(a)那些创造很多节点的攻击(女巫攻击)。(b)保护了之前成功交易节点之间的关系,即使这个节点暂时无法提供数据。(c)最终阻塞那些关系已经恶化的节点之间的通信,直到他们被再次证明。

3.4.3 BitSwap账本

BitSwap节点保存了与其它节点核算传输的账本。这个可以让节点追踪历史记录以及避免被篡改。当激活了一个链接,BitSwap节点就会互换它们账本信息。如果它并不准确匹配,分类账本将会重新初始化,失去那些应记信用和债务。 恶意节点会有意去失去“这些“账本,从而期望清除自己的债务。节点是不太可能在失去了应计信用的情况下还能保证累积足够的债务。然而合作伙伴节点可以自由的将其视为不当行为,拒绝交易。

type?Ledger?struct?{ owner?NodeId?partner?NodeIdbytes_sent?int bytes_recv?int timestamp?Timestamp}

节点可以自由的保存账本的历史记录,尽管正确的操作并不需要这些历史账本。只有当前账本的条目才是有用的。节点也可以根据需要自由对帐本进行垃圾回收,从不太有用的分布式帐本开始:旧的(对等节点可能不存在)和小的。

3.4.4 BitSwap详解

BitSwap节点有以下简单的协议。

//Additional?state?kept?type?BitSwap?struct{ ledgersmap?[NodeId]Ledger?//Ledgers?known?to?this?node,?inc?inactive?active?map[NodeId]Peer?//currently?open?connections?to?other?nodesneed_list?[]Multihash?//check?sums?of?blocks?this?node?needs?have_list?[]Multihash?//check?sums?of?blocks?this?node?has} type?Peer?struct{ nodeid?NodeId ledger?Ledger?//Ledger?between?the?node?and?this?peerlast_seen?Timestamp?//time?stamp?of?last?received?messagewant_list?[]Multihash//check?sums?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);}

对等节点连接的生命周期的概述:1. 打开:对等节点发送账本,直到它们都同意为止。2. 发送:对等节点互换需求列表(want_lists)和数据块。3. 关闭:对等节点关闭连接4. 忽略:(特殊的)如果一个节点的策略是避免发送,那么对待节点将会被忽略(在超时的这段期间内)

1)Peer.open (NodeId, Ledger).当连接的时候,节点会初始化一个与账本的连接,该账本要么是过去保存的账本,要么是一个全新的账本。然后,发送一个携带账本的open信息给对等节点。

接收到一个open信息之后,对等节点可以选择是否接受此连接。如果,根据接收者的账本,发送者是一个不可信的代理(传输低于零或者有很大的未偿还的债务),接收者可能会选择忽略这个请求。忽略请求是通过ignore_cooldown超时来概率性实现的,以便让错误能够有时间改正和攻击者被挫败。

如果连接被激活,接收者将使用本地版本的账本来初始化一个Peer对象,以及设置last_seen时间戳。然后,它会将接收到的账本与自己的账本进行比较。如果两个账本完全匹配,那么这个连接就被Open,如果账本并不完全匹配,那么此节点会创建一个全新的账本并且将其发出去。

2)Peer.send_want_list(WantList).当连接已经Open的时候,节点会广播它们的want_list给所有已经连接的对等节点。这个是在(a)open连接后(b)随机间歇超时后(c)want_list改变后(d)接收到一个新的块之后完成的。

当接收到一个want_list之后,节点会存储它。然后,会检查自己是否拥有任何它想要的块。如果有,会根据上面提到的BitSwap策略来将want_list所需要的块发送出去。

3)Peer.send_block(Block).发送一个块是直接了当的。节点只是简单地传输数据块。当接收到了所有数据的时候,接收者会计算多重hash用以验证是否是自己所需数据,然后发送确认信息。

在完成一个正确的块传输之后,接受者会将此块从need_list一到have_list,最后接收者和发送者都会更新它们的账本来反映出传输的额外数据字节数。

如果一个传输验证失败了,发送者要么会出故障要么会攻击接收者,接收者可以选择拒绝后面的交易。注意,BitSwap是期望能够在一个可靠的传输通道上进行操作的,所以传输错误(可能会引起一个对诚实发送者错误的惩罚)是期望在数据发送给BitSwap之前能够被捕捉到。

4)Peer.close(Bool).传给close最后的一个参数,代表close链接是否是发送者的意愿。如果参数值为false,接收者可能会立即重新open链接,这避免链过早的close链接。

一个对等节点close链接发生在下面两种情况下:1. silence_wait超时已经过期,并且没有接收到来自于对等节点的任何信息(BitSwap默认使用30秒),节点会发送Peer.close(false)。2. 在节点退出和BitSwap关闭的时候,节点会发送Peer.close(true).

接收到close消息之后,接收者和发送者会断开链接,清除所有被存储的状态。账本可能会被保存下来为了以后的便利,当然,只有在被认为账本以后会有用时才会被保存下来。

注意:非open信息在一个不活跃的连接上应该是被忽略的。在发送send_block信息时,接收者应该检查这个块,看它是否是自己所需的,并且是否是正确的,如果是,就使用此块。总之,所有不规则的信息都会让接收者触发一个close(false)信息并且强制性的重初始化此链接。

3.5 Merkle DAG对象

DHT和BitSwap允许IPFS构造一个庞大的点对点系统用来快速稳定的分发和存储。最主要的是,IPFS建造了一个Merkle DAG,一个无回路有向图,对象之间的links都是hash加密嵌入在源目标中。这是Git数据结构的一种推广。Merkle DAGS给IPFS提供了很多有用的属性,包括:1. 内容可寻址:所有内容都是被多重hash校验和来唯一识别的,包括links。2. 防止篡改:所有的内容都用它的校验和来验证。如果数据被篡改或损坏,IPFS会检测到。3. 重复数据删除:所有的对象都拥有相同的内容并只存储一次。这对于索引对象非常有用,比如git的tree和commits,或者数据的公共部分。IPFS对象的格式是:

type?IPFSLink?struct?{Name?string//?name?or?alias?of?this?linkHash?Multihash//?cryptographic?hash?of?targetSize?int//?total?size?of?target}type?IPFSObject?struct?{links?[]IPFSLink//?array?of?linksdata?[]byte//?opaque?content?data}

IPFS Merkle DAG是存储数据非常灵活的一种方式。只要求对象引用是(a)内容可寻址的,(b)用上面的格式编码。IPFS允许应用完全的掌控数据域;应用可以使用任何自定义格式的数据,即使数据IPFS都无法理解。单独的内部对象link表允许IPFS做:

用对象的形式列出所有对象引用,例如:

>?ipfs?ls?/XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzbXLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x?189458?lessXLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5?19441?scriptXLF4hwVHsVuZ78FZK6fozf8Jj9WEURMbCX4?5286?template<object?multihash>?<object?size>?<link?name>

解决字符串路经查找,例如foo/bar/baz。给出一个对象,IPFS会解析第一个路经成分进行hash放入到对象的link表中,再获取路径的第二个组成部分,一直如此重复下去。因此,任何数据格式的字符串路经都可以在Merkle DAG中使用。

递归性的解决所有对象引用:

>?ipfs?refs?--recursive?\/XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzbXLLxhdgJcXzLbtsLRL1twCHA2NrURp4H38sXLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16xXLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z...

原始数据结构公共link结构是IPFS构建任意数据结构的必要组成部分。可以很容易看出Git的对象模型是如何套用DAG的。一些其他潜在的数据结构:(a)键值存储(b)传统关系型数据(c)数据三倍存储(d) 文档发布系统(e)通信平台(f)加密货币区块。这些系统都可以套用IPFS Merkle DAG,这使这些系统更复杂的应用可以使用IPFS作为传输协议。

3.5.1 路径

IPFS对象可以遍历一个字符串路经。路经格式与传统UNIX文件系统以及Web一致。Merkle DAG的links使遍历变得很容易。全称路经在IPFS中的格式是:

#?format/ipfs/<hash-of-object>/<name-path-to-object>#?example/ipfs/XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x/foo.txt

/ipfs前缀允许只要在挂载点不冲突(挂载点名称当然是可配置的)的情况下挂载到一个已存在的系统上。第二个路经组成部分(第一个是IPFS)是一个对象的hash。通常都是这种情况,因为没有全局的根。一个根对象可能会有一个不可能完成的任务,就是在分布式环境(可能还断开链接)中处理百万对象的一致性。因此,我们用地址可寻址来模拟根。通过的hash所有的对象都是可访问的。这意思是说,给一个路经对象/bar/baz,最后一个对象可以可以被所有的访问的:

/ipfs/<hash-of-foo>/bar/baz/ipfs/<hash-of-bar>/baz/ipfs/<hash-of-baz>

3.5.2 本地对象

IPFS客户端需要一个本地存储器,一个外部系统可以为IPFS管理的对象存储以及检索本地原始数据。存储器的类型根据节点使用案例不同而不同。在大多数情况下,这个存储器只是硬盘空间的一部分(不是被本地的文件系统使用键值存储如leveldb来管理,就是直接被IPFS客户端管理),在其他的情况下,例如非持久性缓存,存储器就是RAM的一部分。最终,所有的块在IPFS中都是能够获取的到的,块都存储在了一些节点的本地存储器中。当用户请求一个对象时,这个对象会被查找到并下载下来存储到本地,至少也是暂时的存储在本地。这为一些可配置时间量提供了快速的查找。

3.5.3 对象锁定

希望确保特定对象生存的节点可以锁定此对象。这保证此特定对象被保存在了节点的本地存储器上。也可以递归的进行锁定所有相关的派生对象。这使所有被指定的对象都保存在本地存储器上。这对长久保存文件特别有用,包括引用。这也同样让IPFS成为一个links是永久的Web,且对象可以确保其他被指定对象的生存。

3.5.4 发布对象

IPFS是全球分布的。它设计为允许成千上万的用户文件可以共同的存在的。DHT使用内容哈希寻址技术,使发布对象是公平的,安全的,完全分布式的。任何人都可以发布对象,只需要将对象的key加入到DHT中,并且以对象是对等节点的方式加入进去,然后把路径给其他的用户。要注意的是,对象本质上是不可改变的,就像在Git中一样。新版本的哈希值不同,因此是新对象。跟踪版本则是额外版本对象的工作。

3.5.5 对象级别的加密

IPFS是具备可以处理对象级别加密操作的。一个已加密的或者已签名的对象包装在一个特殊的框架里,此框架允许加密和验证原始字节。

type?EncryptedObject?struct?{Object?[]bytes//?raw?object?data?encryptedTag?[]bytes//?optional?tag?for?encryption?groups}type?SignedObject?struct?{Object?[]bytes//?raw?object?data?signedSignature?[]bytes//?hmac?signaturePublicKey?[]multihash//?multihash?identifying?key}

加密操作改变了对象的哈希值,定义一个不同的新的对象。IPFS自动的验证签名以及使用用户指定的钥匙链解密数据。加密数据的links也同样的被保护着,没有解密秘钥就无法遍历对象。也存在着一种现象,可能父对象使用了一个秘钥进行了加密,而子对象使用了另一个秘钥进行加密或者根本没有加密。这可以保证links共享对象安全。

3.6 文件

IPFS在Merkle DAG上还为模型化版本文件系统定义了一组对象。这个对象模型与Git比较相似:1. Block:一个可变大小的数据块2. List:块或者其他链表的集合3. Tree:块,链表,或者其他树的集合4. Commit:树在版本历史记录中的一个快照

我原本希望使用与Git对象格式一致的模型,但那就必须要分开来引进在分布式文件系统中有用的某些特征,如(a)快速大小查找(总字节大小已经加入到对象中)(b)大文件的重复删除(添加到list对象)(c)commits嵌入到trees中。不过,IPFS文件对象与Git还是非常相近的,两者之间进行交流都是有可能的。而且,Git的一个系列的对象可以被引进过来转换都不会丢失任何的信息。(UNIX文件权限等等)。

标记:下面的文件对象格式使用JSON。注意,虽然IPFS包含了JSON的互相转换,但是文件对象的结构体还是使用protobufs的二进制编码。

3.6.1 文件对象:blob

blob对象代表一个文件且包含一个可寻址的数据单元,IPFS的blobs就像Git的blobs或者文件系统数据块。它们存储用户的数据。需要留意的是IPFS文件可以使用lists或者blobs来表示。Blobs没有links。

{"data":?"some?data?here",//?blobs?have?no?links}

3.6.2 文件对象:list

List对象代表着由几个IPFS的blobs连接成的大文件或者重复数据删除文件。Lists包含着有序的blob序列或list对象。从某种程度上而言,IPFS的list函数就像一个间接块的文件系统。由于lists可以包含其他的lists,那么包含linked的链表和平衡树的拓扑结构是有可能的。有向图中相同的节点出现在多个不同地方允许在文件中重复数据删除。当然,循环是不可以能的,因为是被哈希寻址强制实行的。

{"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]}

3.6.3 文件对象:tree

IPFS中的tree对象与Git中相似,它代表着一个目录,一个名字到哈希值的映射。哈希值则表示着blobs,lists,其他的trees,或者commits。注意,传统路径的命名早已经被Merkle DAG实现了。

{"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]}

3.6.4 文件对象:commit

IPFS中的commit对象代表任何对象在版本历史记录中的一个快照。与Git中类似,但是它能够表示任何类型的对象。它同样link着发起对象。

{"data":?{"type":?"tree","date":?"2014-09-20?12:44:06Z","message":?"This?is?a?commit?message."},?"links":?[ {?"hash":?"XLa1qMBKiSEEDhojb9FFZ4tEvLf7FEQdhdU","name":?"parent",?"size":?25309?}, {?"hash":?"XLGw74KAy9junbh28x7ccWov9inu1Vo7pnX","name":?"object",?"size":?5198?}, {?"hash":?"XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm","name":?"author",?"size":?109?}] } >?ipfs?file-cat?<ccc111-hash>?--json {"data":?{"type":?"tree","date":?"2014-09-20?12:44:06Z","message":?"This?is?a?commit?message."},?"links":?[{?"hash":?"<ccc000-hash>","name":?"parent",?"size":?25309?},{?"hash":?"<ttt111-hash>","name":?"object",?"size":?5198?},{?"hash":?"<aaa111-hash>","name":?"author",?"size":?109?}] }

>?ipfs?file-cat?<ttt111-hash>?--json {"data":?["tree",?"tree",?"blob"],"links":?[{?"hash":?"<ttt222-hash>","name":?"ttt222-name",?"size":?1234?},{?"hash":?"<ttt333-hash>","name":?"ttt333-name",?"size":?3456?},{?"hash":?"<bbb222-hash>","name":?"bbb222-name",?"size":?22?}]}

>?ipfs?file-cat?<bbb222-hash>?--json {"data":?"blob222?data","links":?[]?}

3.6.5 版本控制

Commit对象代表着一个对象在历史版本中的一个特定快照。在两个不同的commit中比较对象(和子对象)可以揭露出两个不同版本文件系统的区别。只要commit和它所有子对象的引用是能够被访问的,所有前版本是可获取的,所有文件系统改变的全部历史是可访问的,这就与Merkle DAG对象模型脱离开来了。

Git版本控制工具的所有功能对于IPFS的用户是可用的。对象模型不完全一致,但也是可兼容的。这可能(a)构建一个Git工具版本改造成使用IPFS对象图,(b)构建一个挂载FUSE文件系统,挂载一个IPFS的tree作为Git的仓库,把Git文件系统的读/写转换为IPFS的格式。

3.6.6 文件系统路径

如我们在Merkle DAG中看到的一样,IPFS对象可以使用字符串路径API来遍历。IPFS文件对象是特意设计的,为了让挂载IPFS到UNIX文件系统更加简单。文件对象限制trees没有数据,为了使它们可以表示目录。Commits可以以代表目录的形式出现,也可以完全的隐藏在文件系统中。

3.6.7 将文件切割成Lists和Blob

版本控制和分发大文件其中一个最主要的挑战是:找到一个正确的方法来将它们分隔成独立的块。与其认为IPFS可以为每个不同类型的文件提供正确的分隔方法,不如说IPFS提供了以下的几个可选选择:就像在LIBFS[?]中一样使用Rabin Fingerprints [?]来选择一个比较合适的块边界。使用rsync[?] rolling-checksum算法,来检测块在版本之间的改变。允许用户指定专为特定文件而调整的’快分隔’函数。

3.6.8 路径查找性能

基于路径的访问需要遍历对象图。获取每个对象要求在DHT中查找它们的key,连接到对等节点,然后获取它的块。这造成相当大的开销,特别是查找的路径由很多子路径组成时。下面的方法可以减缓开销:

tree缓存:由于所有的对象都是哈希寻址的,它们可以被无限的缓存。另外,trees一般比较小,所以比起blobs,IPFS会优先缓存trees。

flattened trees:对于任何tree,一个特殊的 flattened tree可以构建一个链表,所有对象都可以从这个tree中访问得到。在flattened tree中名字就是一个从原始tree分离的路径,用斜线分隔。

例如,对于上面的ttt111的flattened tree如下:

{?"data":["tree",?"blob",?"tree",?"list",?"blob"?"blob"], "links":?[{?"hash":?"<ttt222-hash>",?"size":?1234"name":?"ttt222-name"?},{?"hash":?"<bbb111-hash>",?"size":?123,"name":?"ttt222-name/bbb111-name"?},{?"hash":?"<ttt333-hash>",?"size":?3456,"name":?"ttt333-name"?},{?"hash":?"<lll111-hash>",?"size":?587,"name":?"ttt333-name/lll111-name"},{?"hash":?"<bbb222-hash>",?"size":?22,"name":?"ttt333-name/lll111-name/bbb222-name"?},{?"hash":?"<bbb222-hash>",?"size":?22"name":?"bbb222-name"?}]}

3.7 IPNS:命名以及易变状态

目前为止,IPFS桟形成了一个对等块交换组成一个内容可寻址的DAG对象。这提供了发布和获取不可改变的对象。这甚至可以跟踪这些对象的版本历史记录。但是,这里有一个关键成分遗漏了:可变的命名。没有这个,发送IPFS的links,所有新内容的通信肯定都会有所偏差。现在所需就是能有某些方法可以获取相同路径的的可变状态。这值得详述原因—如果最终易变数据是必须的—我们费了很大的力气构建了一个不可改变的Merkle DAG。就当做IPFS脱离了Merkle DAG的特征:对象可以(a)通过哈希值可以获取(b)完整性的检查(c)链接其他的对象(d)无限缓存。从某种意义上说:对象就是永恒的。

这些就是一个高性能分布式系统的关键特征,在此系统上跨网络links之间移动文件是非常昂贵的。对象内容可寻址构建了一个具有以下特点的Web,(a)优秀的宽带优化(b)不受信任的内容服务(c)永恒的links(d)能够永久备任何对象以及它的引用。

不可变的内容可寻址对象和命名的Merkle DAG, 可变指针指向Merkle DAG,实例化了一个出现在很多成功分布式系统中的二分法。这些系统包括Git的版本控制系统,使用不可变的对象和可变的引用;还有UNIX分布式的继承者Plan9[?]文件系统,使用可变的Fossil和不可变的Venti[?]。LBFS[?]同样使用可变的索引以及不可变的块。

3.7.1 自我认证命名

使用SFS[12,11]中的命名方案,给我们提供了一种在加密分配的全局命名空间中构建可变的自我认证名称的方法,。IPFS的方案如下:1. 回顾一下在IPFS中:NodeId = hash(node.PubKey)2. 我们给每个用户分配一个可变的命名空间,在此路径下:/ipns/3. 一个用户可以在此路径下发布一个用自己私钥签名的对象,比如说:/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/4. 当其他用户获取对象时,他们可以检测签名是否与公钥和NodeId匹配。这个验证了用户发布对象的真实性,达到了可变状态的获取。

注意下面的细节:1)IPNS(InterPlanetary的命名空间)分开前缀是在可变和不可变的路径之间建立一个很容易辨认的区别,为了程序也为了人类阅读的便利。

2)因为这不是一个内容可寻址的对象,所以发布它就要依靠IPFS中的唯一的可变状态分配制度,路由系统。过程是(a)首先把此对象做一个常规的不可变IPFS的对象来发布(b)将此对象的哈希值作为元数据的值发布到路由系统上:routing.setValue(NodeId, <ns-object-hash>)3)发布的对象中任何links在命令空间中充当子名称:/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm//ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/docs/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm/docs/ipfs4)一般建议发布一个commit对象或者其他对象的时候,要使用历史版本记录,因为这样就用户就可以找到之前使用过的名字。不过由于这并不总是需要的,所以留个用户自己选择。

注意当用户发布一个对象的时候,无法以相同的方式发布它。

3.7.2 人类友好名称

IPNS的确是一个分配和重新分配名称的好方法,但是对用户却不是十分友好的,因为它使用很长的哈希值作为名称,众所周知这样的名称很难被记住。IPNS足够应付URLs,但对于很多线下的传输工作就没有这么好用了。因此,IPFS使用下面的技术来增加IPNS的用户友好度。

对等节点Links被SFS所鼓舞,用户可以直接将其他用户的对象link到自己的对象上(命令空间,家目录等等)。这有一个好处就是创建了一个可信任的Web(也支持老的真实性认证模型):

#?Alice?links?to?bob?Bobipfs?link?/<alice-pk-hash>/friends/bob?/<bob-pk-hash>#?Eve?links?to?Aliceipfs?link?/<eve-pk-hash/friends/alice?/<alice-pk-hash>#?Eve?also?has?access?to?Bob/<eve-pk-hash/friends/alice/friends/bob#?access?Verisign?certified?domains/<verisign-pk-hash>/foo.com

如果/ipns/是一个有效的域名称,IPFS会在DNS TXT记录中查找关键的ipns。IPFS会将查找到的值翻译为一个对象的哈希值或者另一个ipns的路径:

#?this?DNS?TXT?recordipfs.benet.ai.?TXT?"ipfs=XLF2ipQ4jD3U?..."#?behaves?as?symlinkln?-s?/ipns/XLF2ipQ4jD3U?/ipns/fs.benet.ai

总是会有将二进制编码翻译成可读文件的方法。IPNS则支持Proquint[?].。如下:

#?this?proquint?phrase/ipns/dahih-dolij-sozuk-vosah-luvar-fuluh#?will?resolve?to?corresponding/ipns/KhAwNprxYVxKqpDZ

缩短名称服务会涌现出很多服务器提供缩短名称的服务,向用户提供他们的命名空间。就像我们现在看到的DNS和Web的URLs:

#?User?can?get?a?link?from/ipns/shorten.er/foobar#?To?her?own?namespace/ipns/XLF2ipQ4jD3UdeX5xp1KBgeHRhemUtaA8Vm

3.8 使用IPFS

IPFS设计为可以使用多种不同的方法来使用的,下面就是一些我将会继续追求的使用方式:1.作为一个挂载的全局文件系统,挂载在/ipfs和/ipns下2.作为一个挂载的个人同步文件夹,自动的进行版本管理,发布,以及备份任何的写入3.作为一个加密的文件或者数据共享系统4.作为所有软件的版本包管理者5.作为虚拟机器的根文件系统6.作为VM的启动文件系统 (在管理程序下)7.作为一个数据库:应用可以直接将数据写入Merkle DAG数据模型中,获取所有的版本,缓冲,以及IPFS提供的分配8.作为一个linked(和加密的)通信平台9.作为一个为大文件的完整性检查CDN(不使用SSL的情况下)10.作为一个加密的CDN11.在网页上,作为一个web CDN12.作为一个links永远存在新的永恒的Web

IPFS实现的目标:(a)一个IPFS库可以导出到你自己应用中使用(b)命令行工具可以直接操作对象(c)使用FUSE[?]或者内核的模型挂载文件系统

4. 未来

IPFS的思想是几十年成功的分布式系统的探索和开源的产物。IPFS综合了很多迄今为止很成功的系统中优秀的思想。除了BitSwap新协议之外,IPFS最大的特色就是系统的耦合以及设计的综合性。

IPFS是对去中心化网络基础设施的一个宏伟设想,很多不同类型的应用都可以建立在IPFS上。至少,它可以用作全局,可挂载,版本控制文件系统和命名空间,或者作为下一代的文件共享系统。而最好的情况是,IPFS可以让Web升级一个层次,当发布一个有价值的信息时,任何感兴趣的人都可以进行发布而不会强迫性的必须只允许发布机构进行发布,用户可以信任信息的内容,而无需与发送信息节点建立信任,还有一个特点就是,一些重要但很老的文件也不会丢失。IPFS期待着带我们进入到一个永恒Wdb的世界。

5. 感谢

IPFS是很多伟大的想法和系统的融合。如果没有站在这些巨人的肩膀上,IPFS也不可能敢于有一个这么有野心的目标。感谢参与这些想法长期讨论的人:David Dalrymple, Joe Zimmerman, and Ali Yahya,特别是:揭开Merkle DAG的总体架构(David, Joe),滚动哈希阻塞(David), s/kademlia sybill 保护(David, Ali),特别感谢David Mazieres,为他之前杰出的想法

6. 将来需要完善内容

7. 引用

[1] I. Baumgart and S. Mies. S/kademlia: A practicable approach towards secure key-based routing. In Parallel and Distributed Systems, 2007 International Conference on, volume 2, pages 1–8. IEEE, 2007.[2] I. BitTorrent. Bittorrent and A? ?ttorrent software surpass 150 million user milestone, Jan. 2012.[3] B. Cohen. Incentives build robustness in bittorrent. In Workshop on Economics of Peer-to-Peer systems, volume 6, pages 68–72, 2003.[4] J. Dean and S. Ghemawat. leveldb–a fast and lightweight key/value database library by google, 2011.[5] M. J. Freedman, E. Freudenthal, and D. Mazieres. Democratizing content publication with coral. In NSDI, volume 4, pages 18–18, 2004.[6] J. H. Howard, M. L. Kazar, S. G. Menees, D. A. Nichols, M. Satyanarayanan, R. N. Sidebotham, and M. J. West. Scale and performance in a distributed file system. ACM Transactions on Computer Systems (TOCS), 6(1):51–81, 1988.[7] J. Kubiatowicz, D. Bindel, Y. Chen, S. Czerwinski, P. Eaton, D. Geels, R. Gummadi, S. Rhea,H. Weatherspoon, W. Weimer, et al. Oceanstore: An architecture for global-scale persistent storage. ACM Sigplan Notices, 35(11):190–201, 2000.[8] D. Levin, K. LaCurts, N. Spring, andB. Bhattacharjee. Bittorrent is an auction: analyzing and improving bittorrent’s incentives. In ACM SIGCOMM Computer Communication Review, volume 38, pages 243–254. ACM, 2008.[9] A. J. Mashtizadeh, A. Bittau, Y. F. Huang, andD. Mazieres. Replication, history, and grafting in the ori file system. In Proceedings of the Twenty-Fourth ACM Symposium on Operating Systems Principles, pages 151–166. ACM, 2013.[10] P. Maymounkov and D. Mazieres. Kademlia: A peer-to-peer information system based on the xor metric. In Peer-to-Peer Systems, pages 53–65. Springer, 2002.[11] D. Mazieres and F. Kaashoek. Self-certifying file system. 2000.[12] D. Mazieres and M. F. Kaashoek. Escaping the evils of centralized control with self-certifying pathnames. In Proceedings of the 8th ACM SIGOPS European workshop on Support for composing distributed applications, pages 118–125. ACM, 1998.[13] J. Rosenberg and A. Keranen. Interactive connectivity establishment (ice): A protocol for network address translator (nat) traversal for offer/answer protocols. 2013.[14] S. Shalunov, G. Hazel, J. Iyengar, and M. Kuehlewind. Low extra delay background transport (ledbat). draft-ietf-ledbat-congestion-04. txt, 2010.[15] R. R. Stewart and Q. Xie. Stream control transmission protocol (SCTP): a reference guide. Addison-Wesley Longman Publishing Co., Inc., 2001.[16] L. Wang and J. Kangasharju. Measuring large-scale distributed systems: case of bittorrent mainline dht. In Peer-to-Peer Computing (P2P), 2013 IEEE Thirteenth International Conference on, pages 1–10. IEEE, 2013.

翻译者:

区块链高级工程师、go语言工程师、IPFS早期研究者。网络著书有《IPFS一问一答》、《IPFS操作教程》、《区块链密码学》、《区块链共识算法》;跟踪并翻译报道《IPFS Weekly》,研究并翻译IPFS、Filecoin白皮书,业界知名专家学者——张默默老师!

—-

编译者/作者:Online

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...