IPFS(InterPlanetary File System,星际文件系统),是一个面向整个互联网、基于点对点传输的去中心化分布式文件系统。通过对网络通信、数据处理方法和传输协议等过程的封装,IPFS 能够将运行在多种异构网络上的节点存储资源组织起来,同时向每个节点提供整个 IPFS 网络的存取服务。白皮书中列出了如下几个特点:

  • 点对点传输
  • 去中心化
  • 文件共享
  • 内容去重
  • 基于内容寻址
  • 文件版本控制

IPFS 的设计者希望创建一个数据持久且分布式存储的网络传输协议,能够解决 HTTP 协议所存在的一系列问题(IPFS 官网上的介绍就有对标 HTTP 协议)。举例来说, HTTP 具有超中心化的趋势,尤其是在云计算兴起之后,用户访问数据时,一次只能从一个节点获取所需的数据,如果这个节点故障,就会出现访问错误。针对这一情况,通常的做法是数据冗余备份。此外,单一服务器的负载有限,而 HTTP 无法从多台服务器同时获取数据。

IPFS 的还一个好处是,整个互联网上充斥着大量重复的数据段,IPFS 能够对重复的数据块进行去重。这是 HTTP 无法办到的。下面我们对 IPFS 做一个简单的介绍。


目录

  • (1) IPFS 协议栈
  • (2) IPFS 层级架构
  •  (2.1) Multiformats 模块简述
  •  (2.2) libp2p 模块简述
  •  (2.3) IPLD 模块简述
  • (3) Multiformats
  •  (3.1) multihash 协议 - 统一哈希值
  •  (3.2) multiaddr 协议 - 统一网络地址
  •  (3.3) multibase 协议 - 统一二进制编码
  •  (3.4) multicodec 协议 - 统一字符编码
  •  (3.5) multistream
  •  (3.6) multigram
  •  (3.7) multikey
  • (4) libp2p
  •  (4.1) Peer Routing - 节点对等路由
  •  (4.2) Swarm - 连接管理
  •  (4.3) Distributed Record Store - 节点记录
  •  (4.4) Discovery - 节点发现
  •  (4.5) 核心数据结构
  • (5) IPLD
  •  (5.1) CID(content identifier) - 基于内容寻址的自描述标识
  •  (5.2) IPLD Path v1
  •  (5.3) IPLD Data Model

1. IPFS 协议栈

关于协议分层,网络上能找到几种版本的分层图。其中 IPFS 白皮书中描述的是 7 层结构;GitHub 的 ipfs/specs 仓库中则是分为了 5 层;一些博客中的介绍将其分为 8 层。其中 5 层结构的划分方式将身份认证合并到了网络、将 File 和 Object 统一合并到了 MerkleDAG 中。以下分层采取白皮书的7层结构。

IPFS协议栈.jpg


2. IPFS 层级架构

下图是取自网络的 IPFS 族谱关系图,几个独立的项目共同组成了整个 IPFS 应用。

IPFS族谱关系.jpg

IPFS 的下层由三个独立的子项目组成,即 Multiformats、libp2p、IPLD。Multiformats 在 IPFS 体系中主要负责身份的加密和数据的自我描述;libp2p 项目实现数据的定位和点对点的数据交换;IPLD 项目定义了基于内容寻址的统一数据结构类型,能够将现有的异构数据结构统一成一种格式,用于实现文件系统的对象组织。如下网图所示。

IPFS协议栈独立项目划分.png

2.1 Multiformats 模块简述

Mutiformats 是对各种不同格式协议/数据的封装,包括不同的哈希算法、网络地址、二进制编码、字符编码等。例如 multihash 是一系列 hash 加密算法和自描述方式(从值上就可以知道值是如何生成)的集合,它具有 SHA1、SHA256、SHA512、Blake3B 等 6 种主流的加密方式,用以加密和描述节点以及指纹数据的生成。

2.2 libp2p 模块简述

libp2p 是 IPFS 数据传输的核心,面对各式各样的传输层协议以及复杂的网络设备,它可以帮助开发者迅速建立一个可用 P2P 网络层,快速且节约成本。libp2p 包含了三层协议:分别是网络、路由、交换。对三层协议的描述如下:

  • 网络层 - IPFS 可以使用任何网络传输协议,因此可以在任何网络上运行,并管理传输、可靠性、连接性、完整性和真实性。其中地址使用 multiaddr(multiformats 层提供)进行封装,向上提供统一的地址格式;
  • 路由层 - IPFS 网络中的节点需要能够找到其他对等体的网络地址和可以提供某些特定数据的对等体。为此,IPFS 使用基于 S/Kademlia 和 Coral 的分布式哈希表(DHT)。DHT 可实现高效查找,同时有效利用存储和带宽;
  • 交换层 - IPFS 使用类似于 BitTorrent 的协议进行数据交换,称为 BitSwap。数据被分解为块并在节点之间交换。

2.3 IPLD 模块简述

IPLD 是一个转换层中间件,将现有的异构数据结构统一成一种格式,方便不同系统之间的数据交换和互操作。IPLD 实现了最上面的三层协议:对象、文件、命名。

  • 对象层 - IPFS 中的数据以 Merkle Directed Acyclic Graph(Merkle DAG)的结构组织,节点称为对象,可以包含数据或指向其他对象的链接,链接是嵌入在源中的目标数据的加密哈希。这些数据结构提供了许多有用的属性,如内容寻址、数据防篡改、重复数据删除等;
  • 文件层 - 为了在 Merkle DAG 之上建模一个类似 Git 的版本控制系统,IPFS 定义了如下的对象:

    • blob 数据块:blob 是一个可变大小的数据块(无链接),代表一个数据块;
    • list:用于有序地组织 blob 或其他 lists,通常代表一个文件;
    • tree:代表目录并包含 blobs、lists 以及其他 trees;
    • commit:类似于 Git 的提交,表示对象的版本历史记录中的快照;
  • 命名层 - 由于对象的每次更改都会改变其哈希值,因此需要对哈希值做一个映射。IPNS(Inter Planetary 命名空间系统)为每个用户分配一个可变的命名空间,并且可以将对象发布到由用户私钥签名的路径,以验证对象的真实性。类似 URL。

3. Multiformats

Multiformats 是一系列协议的集合,它将一系列不同格式的协议进行封装,以统一的格式提供给上层使用。里面包含以下七个大类:

  • multihash - 自描述哈希
  • multiaddr - 自描述网络地址
  • multibase - 自描述基编码
  • multicodec - 自描述序列化
  • multistream - 自描述流网络协议
  • multigram (WIP) - 自描述分组网络协议
  • multikey - 用于加密密钥的协议

3.1 multihash 协议 - 统一哈希值

multihash 在现有的协议基础上对数据块的哈希值进行统一封装,即从哈希值就可以知道该值是如何产生的。Multiformats 将所有的哈希值计算统一成同样的格式,这种方式能够保证对多种不同的哈希算法保持兼容,即使未来旧的哈希算法被淘汰,仍然能保证对新算法的兼容,这种封装方式为系统开发带来很多好处。

multihash 格式定义(遵循 TLV <类型-长度-值> 的模式):

<hash-func-type><digest-length><digest-value>
  • 类型 <hash-func-type> 是一个标识散列函数的无符号变量整数;
  • 长度 <digest-length> 是一个无符号变量整数,用于计算哈希值的长度(以字节为单位);
  • 值 <digest-value> 是哈希值,其长度恰好是 <digest-length> 字节;

例如:

122041dd7b6443542e75701aa98a0c235951a28a0d851b11564d20022ab11d2589a8
哈希函数类型: sha2-256 (code in hex: 0x12)
长度: 32 (in hex: 0x20)
哈希值: 41dd7b6443542e75701aa98a0c235951a28a0d851b11564d20022ab11d2589a8

目前支持的哈希函数类型值有:

sha1 (code in hex: 0x11)
sha2-256 (code in hex: 0x12)
sha2-512 (code in hex: 0x13)
sha2-512 (code in hex: 0x13)
blake2b-512 (code in hex: 0xb240)
blake2b-256 (code in hex: 0xb220)
blake2s-256 (code in hex: 0xb260)
blake2s-128 (code in hex: 0xb250)

3.2 multiaddr 协议 - 统一网络地址

为了支持不同的网络类型,所以设计 multiaddr 对不同的网络类型进行封装。multiaddr 采用的是 TLV+ 的编码模式,有两种格式:

  • 便于人类阅读的打印格式(UTF-8)

路径以递归的形式嵌套协议和地址:

(/<addr-protocol-str-code>/<addr-value>)+
<addr-protocol-str-code>:协议字符串
<addr-value>:适用于该协议的网络地址
()+:递归嵌套其他协议

例如:

/ip4/127.0.0.1/udp/9090/quic
/ip6/::1/tcp/3217
/ip4/127.0.0.1/tcp/80/http/baz.jpg
/dns4/foo.com/tcp/80/http/bar/baz.jpg
/dns6/foo.com/tcp/443/https
  • 用于传输存储的二进制格式
(<addr-protocol-code><addr-value>)+
<addr-protocol-code>:协议代码,整数形式
<addr-value>:二进制格式的地址值
()+:递归嵌套其他协议

3.3 multibase 协议 - 统一二进制编码

multibase 是用于消除文本中出现的基本编码(例如 base32,base64,base58 等二进制的编码)的协议,其格式为:

<base-encoding-character><base-encoded-data>

其中 <base-encoding-character> 的定义如下表:

encoding,               code,     description
identity,               0x00,     8-bit binary
base1,                  1,        unary (11111)
base2,                  0,        binary (01010101)
base8,                  7,        octal
base10,                 9,        decimal
base16,                 f,        hexadecimal
base16upper,            F,        hexadecimal
base32hex,              v,        rfc4648 no padding - highest char
base32hexupper,         V,        rfc4648 no padding - highest char
base32hexpad,           t,        rfc4648 with padding
base32hexpadupper,      T,        rfc4648 with padding
base32,                 b,       rfc4648 no padding
base32upper,            B,        rfc4648 no padding
base32pad,              c,        rfc4648 with padding
base32padupper,         C,        rfc4648 with padding
base32z,                h,        z-base-32 (used by Tahoe-LAFS)
base58flickr,           Z,        base58 flicker
base58btc,              z,        base58 bitcoin
base64,                 m,        rfc4648 no padding
base64pad,              M,        rfc4648 with padding - MIME encoding
base64url,              u,        rfc4648 no padding
base64urlpad,           U,        rfc4648 with padding

3.4 multicodec 协议 - 统一字符编码

multicodec 用于支持多种类型的编码,其格式为:

<multicodec><encoded-data>

3.5 multistream

解码传入的数据流,定义如下:

<varint-len>/<codec>\n<encoded-data>

例如:

hex:       062f6a736f6e2f7b2268656c6c6f223a22776f726c64227d
ascii:     23/json\n"{\"hello\":\"world\"}"

3.6 multigram

协议协商和数据报复用。还在开发中,文档空白

3.7 multikey

用于加密密钥。还在开发中,文档空白


4. libp2p

libp2p 负责在两个节点之间传递数据块,向上层屏蔽复杂的网络细节。主要包含下面几个模块:

libp2p模块.png

  • Peer Routing - 节点对等路由,负责计算到达某个节点的可用路径
  • Swarm - 连接管理,负责管理节点之间连接的创建、维护、销毁
  • Distributed Record Store - 负责记录节点相关的各种信息,便于连接管理和内容寻址
  • Discovery - 节点发现,负责找到网络里面的可用节点

主要功能总结一句话就是:发现节点 - 连接节点 - 发现数据 - 传输数据。

4.1 Peer Routing - 节点对等路由

对等路由子系统对外公开一个接口,用以识别应将哪些对等体路由到 DHT。项目组提出了两个机制用于实现对等路由,分别基于 Kademlia DHT 和基于 mDNS 实现。

  • kad-routing 实现了 Kademlia Routing table,其中每个对等体拥有一组 k-buckets,每个 k-bucket 包含来自网络中其他对等体的多个 PeerInfo 对象。
  • mDNS-routing 使用 mDNS 探测器来识别本地对等网络节点是否存在。

4.2 Swarm - 连接管理

用于处理 libp2p 中与流相关的所有内容,包括协议多路复用,流式多路复用,NAT遍历和连接中继,同时进行多路传输。libp2p 项目组的文档仓库中,关于 swarm 的部分还没有添加,目前仓库中只列出了如下 6 个标题:

  • Stream Muxer流的多路复用
  • Protocol Muxer 协议多路复用
  • Transport
  • Crypto
  • Identify
  • Relay

4.3 Distributed Record Store - 节点记录

4.3.1 Record
记录本身是一条数据,旨在通过网络传输和存储在各种计算机中。所有记录系统都包括记录有效性的概念,它允许一个 record system 的用户验证记录的值是否正确和有效。记录的有效性可能取决于加密签名,时空范围(例如设定一个时间,当前时间超过该设定的时间即失效)等。

记录系统(Record System)是定义用于通过计算机网络进行 crafting,serializing,distributing,verifying 的方法的协议。描述的原文如下:

  • crafting - construction of a record (the process of calculating the values of a record)
  • serializing - formating a record into a bitstring.
  • distributing - transportation of a record from one set of computers to another.
  • verifying - checking a record's values to ensure correctness and validity.

4.3.2 abstract-record-store
文档空白

4.3.3 kad-record-store
文档空白

4.3.4 mDNS-record-store
文档空白

4.3.5 s3-record-store
文档空白

4.4 Discovery - 节点发现

  • mDNS-discovery 是一种在局域网上使用 mDNS 进行网络发现的协议。它会发出 mDNS 数据包,以查找是否有更多可连接的对等体。mDNS-discovery 是一个独立的协议,不依赖于任何其他 libp2p 协议。
  • Random-Walk 是 DHT(以及具有路由表的其他协议)的发现协议。 它使随机的 DHT 查询能够快速发现大量对等节点。这将使 DHT(或其他协议)以更快的速度收敛。
  • bootstrap-list 也是一种发现协议,它使用本地存储来缓存网络中可用的高度稳定的对等节点的地址。基本上与 DNS 引导自身的方式相同。

4.5 核心数据结构

PrivateKey        节点的私钥。
PublicKey         节点的公钥。
PeerId            节点公钥的哈希值。
PeerInfo          一个包含节点的 PeerId 及其已知的 multiaddrs 的对象。
Transport         用于建立与其他对等节点的连接。
Connection        维持两个节点之间的点对点链接。
Muxed-Stream      双工消息通道。
Stream-Muxer      流的多路复用器。 
Record            用于描述 IPLD 的对象。
multiaddr         自描述描述的网络地址。
multicodec        自描述编码类型。
multihash         自我描述的哈希。

5. IPLD

IPLD 定义了基于内容寻址的统一数据结构类型。它是一个转换器,可以把现有的异构的数据结构(基于内容寻址)统一成一种格式,方便不同系统之间的数据交换和互操作。IPLD 的协议栈如下图所示:

IPLD协议栈.png

5.1 CID(content identifier) - 基于内容寻址的自描述标识

CID 是一段内容经过计算后形成的 ID(基于内容的哈希值),不直接指向内容的存储位置,而是形成一段地址,交由下层 libp2p 进行地址组合,并最终形成一个完整的网络地址。根据项目组的文档描述,CID 有两个版本,分别叫 CIDv0 和 CIDv1,其中 v1 版本为默认版本。

CIDv0 的版本基于 multihash,原始文档中有如下的简述:When IPFS was first designed, we used base 58-encoded multihashes as the content identifiers (This is simpler, but much less flexible than newer CIDs).

CIDv1 的版本包含一些前导标识符,用于说明哪些标识与作为内容的哈希值本身一起使用:

  • A multibase prefix - 指定 CID 后面部分的编码格式;
  • A CID version identifier - 指示这是哪个版本的 CID;
  • A multicodec identifier - 指示目标内容的格式;

CIDv1 完整的格式如下所示:

<mbase><version><mcodec><mhash>

5.2 IPLD Path v1

IPLD Path 是用于 IPLD 图中的深层引用的字符串标识符。Path 分为两类(可以理解成相对路径与绝对路径):

  • full path resolution
  • block level resolution

项目组的文档仓库没有详细说明 Path 的组织形式,这部分可能需要从代码中分析。

5.3 IPLD Data Model

简单类型:

  • Boolean
  • Null
  • String
  • Integer
  • Float
  • Array
  • Object (Hash Map)
  • Binary

链接类型:

  • CID

【TODO】:IPFS 参考了 Kademlia(BitTorrent)、Coral DSHT、S/Kademlia DHT、Merkle DAG 等,其中三个子模块(Multiformats、libp2p、IPLD)以及 IPFS 本身都是单独拉出的独立项目组在搞,文档还很欠缺,因此可能需要对 IPFS 所参考的那几篇文章进行分析。

(完)


参考文献

[1] Benet J. IPFS - Content Addressed, Versioned, P2P File System[J]. Eprint Arxiv, 2014.