理解 IPFS 白皮书 第 1 部分
原文链接:https://decentralized.blog/un...
哦不,白皮书!
加密货币 / 区块链世界喜爱白皮书,IPFS 也不例外。 它起源于著名的由中本聪编写的白皮书 Bitcoin: A Peer-to-Peer Electronic Cash System(反过来又引用了另一篇你不想知道的白皮书)。 当我们深入加密货币时,我们将在后续的文章中看看比特币白皮书。
关于白皮书,你需要了解的两件事:
- 它们以 PDF 格式分发(因为它比 HTML 更难更改!)
- 白皮书很难,看起来很可怕并且包含至少一个数学公式。
IPFS 白皮书原文在这里: IPFS - Content Addressed, Versioned, P2P File System (DRAFT 3) 。 并且,理所应当地托管在 IPFS 上。
要理解 IPFS 的工作原理,最好一步一步地学习白皮书。 我将用两个章节内来一窥 IPFS 的底层技术:
- Distributed Hash Tables 分布式哈希表
- Block Exchanges - BitTorrent 块交换
- Version Control Systems - Git 版本控制系统
- Self-Certified Filesystems - SFS 自我认证的文件系统
对应到 ISO 协议栈如下图:
好了,我们开始吧!
分布式散列表 (DHT)
什么是 DHT?
DHT 就像 Python 中的 dict 对象或 Perl 的哈希(如果你有键,你就可以检索到相应的值),但 DHT 的数据分布在多个节点上。 维基百科文章 Distributed hash table 给出了很好的介绍。
在 IPFS 的例子中,键是内容的哈希。 因此,向 IPFS 节点询问具有哈希 QmcPx9ZQboyHw8T7Afe4DbWFcJYocef5Pe4H3u7eK1osnQ 的内容,于是 IPFS 节点将在 DHT 中查找哪些节点保存了对应的内容。
如何有效地找到特定值(快速,尽可能少的网络请求)以及如何管理 DHT 以便更改(进入 / 离开网络的节点或表中的新条目)容易被承受。这两个问题在已有的 DHT 的实现方式各不相同。
其中一种实现称为 Pastry,我喜欢这两个视频,其中 路由 (如何查找值)和 动态 (如何处理节点添加 / 删除)得到了很好的解释。
Kademlia 和它的朋友们
回到白皮书。 从 Kademlia 开始,白皮书中明确提到了三个 DHT 实现。 Kademlia 有自己的 白皮书 ,但我们暂时不去管。
Kademlia 是几乎所有流行的 P2P 系统中都会使用的 DHT 协议,另外关于 Kedemlia 的 维基百科 也有很好介绍。
简而言之,Kedemlia 使用节点的 ID 逐步接近具有所需哈希的节点(来自维基百科文章):
在搜索某些值时,算法需要知道相关的密钥并分几步探索网络。 每个步骤都会找到更靠近密钥的节点,直到联系的节点返回该值或找不到更近的节点。 这非常有效:与许多其他 DHT 一样,Kademlia 在总共 n 个节点的系统中仅需要联系 O(log(n)) 个节点。
这里面的细节开始变得非常复杂,我认为它不会帮助我们达到理解 IPFS 的目标,所以我们继续前进。 如果你喜欢类似的东西:这里有一个 很好的介绍 ,如果你想深入挖掘 Kademlia 白皮书的链接是 ^^^(译者注:没有理解这个符号的涵义,在和作者沟通中)。
IPFS 白皮书提到了另外两个改进了标准 Kedemlia 的 DHT 实现:
- Coral DSHT:提高查找性能并减少资源使用。
- S/Kademlia:使 Kademlia 更能抵御恶意攻击。
IPFS DHT 实战
DHT 在 IPFS 中用于路由,换句话说:
- 宣布向网络添加数据
- 帮助定位任何节点请求的数据。
白皮书指出:
小值(等于或小于 1KB)直接存储在 DHT 上。 对于更大的值,DHT 存储引用,即存储数据块对等的节点的 ID 值。
那么我们来看一下我们是否可以通过直接访问 DHT 并添加和检索小数据块。
$ ipfs daemon # 确保能成功运行(首先安装配置好 ipfs)
$ echo 'my tiny text' | ipfs add # 向当前节点添加一个小于 1KB 的文本文件
QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF
$ ipfs cat QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF # 检查
my tiny text
$ ipfs dht get /ipfs/QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF
# returns not found
所以现在我们有那个文本,我们想从 DHT 访问它,但显然,支持的 ipfs dht get
请求是以 / ipns / 开头的键。
好的,所以我们创建了一个 IPNS ,看看我们是否可以直接查询:
$ ipfs name publish QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF # point a IPNS address to our content
Published to QmYebHWdWStasXWZQiXuFacckKC33HTbicXPkdSi5Yfpz6: /ipfs/QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF
$ ipfs resolve QmYebHWdWStasXWZQiXuFacckKC33HTbicXPkdSi5Yfpz6 # check it
# never returns, hmm IPNS doesn't seem to be ready for production
$ ipfs dht get /ipns/QmYebHWdWStasXWZQiXuFacckKC33HTbicXPkdSi5Yfpz6 # same thing but directly
# does return binary data starting with 4/ipfs/QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF
它确实有效,但现在似乎仅限于 IPNS 。我们还可以用 DHT 做些什么?
使用 DHT 找出哪些节点可以提供指定的数据:
$ ipfs dht findprovs QmfQKcXMLGvCxx6opNDwb1ptD1LJER6MPHdsMHCB1CXpFF
QmYebHWdWStasXWZQiXuFacckKC33HTbicXPkdSi5Yfpz6
QmRf4ERGvYpVo6HRa2VueZT8pWi8YvyLS3rW6ad2y83tdN
# ^^^ there are both my nodes, so that works
# Now ask the DHT for the address of the first peer that was returned
$ ipfs dht findpeer QmYebHWdWStasXWZQiXuFacckKC33HTbicXPkdSi5Yfpz6
/ip4/176.92.234.78/tcp/4001
/ip4/85.74.239.218/tcp/38689
/ip4/127.0.0.1/tcp/4001
/ip4/192.168.1.30/tcp/4001
/ip6/::1/tcp/4001
/ip4/192.168.1.3/tcp/4001
/ip4/176.92.234.78/tcp/40443
# Oooh nice! We will visit this address notation in the next episode.
总而言之,我们在实践中看到了一些和 DHT 相关的东西,但这项技术不像我希望的那样直观和实用。
是时候转向应用在 IPFS 的下一个令人兴奋的技术了:
BitTorrent
BitTorrent 如何运作?
我们都知道 BitTorrent,但我们中的一些人(对,我也是)需要深入挖掘才能真正理解它。 这个演讲是一个很好的介绍: Feross Aboukhadijeh:WebTorrent - JSConf.Asia 2014 。 演讲者讨论了他如何实现可以在浏览器中运行的 BitTorrent 客户端,这要归功于 WebRTC(一种很酷的技术,可能以后会在我们的项目派上用场)。 它同样彻底阐述了 DHT 的工作机制。
更多资料:
- Peer-to-peer networking with BitTorrent (PDF)。 如果你只想读一篇文章,那就选这篇。
- Peer to Peer Content Delivery - BitTorrent(视频)+ 幻灯片 (PDF)。
- The BitTorrent Protocol Specification v2(标准规范,读起来不会很困难)。
BitTorrent 和 IPFS
IPFS 中的数据(块)交换受 BitTorrent 的启发,但并不是和 BitTorrent 完全一样的机制。 白皮书提到了 IPFS 使用的两个 BitTorrent 的特性:
- tit-for-tat(译者注:针锋相对)的策略(如果你不分享数据,你也不会收到数据)
- 优先获取稀有的数据(提高性能等等,请参阅上面的第一个 PDF)
一个值得注意的区别是,在 BitTorrent 中,每个文件都有单独的一组对等节点(彼此形成一个 P2P 网络),而 IPFS 则是所有数据都在对等节点形成的一个大集群中。 IPFS BitTorrent 的变种被称为 BitSwap,我将在下一篇中讨论它。
我们在实践一下 swarm
吧。
# Make sure you have the daemon running
$ ipfs swarm peers
/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
当你刚启动守护进程时,你会连接到几个 “种子对等节点”。 过了一会儿,对等节点的数量迅速增长。
另一个查询 swarm 的命令:
$ ipfs swarm addrs
QmNRuQrwtGgeVQgndTny4A4Rukg7GR7vzDJrVJxUBfqevk (4)
/ip4/127.0.0.1/tcp/4001
/ip4/172.31.41.39/tcp/4001
/ip4/35.167.26.28/tcp/4001
/ip6/::1/tcp/4001
QmNSJohkvvBVmHeN7KUZnm4X84GA6Znbv6ZmvsTAjbw3AB (5)
/ip4/10.0.1.8/tcp/4001
/ip4/127.0.0.1/tcp/4001
/ip4/174.44.163.74/tcp/16012
/ip6/::1/tcp/4001
/ip6/fd15:462e:f8fd:695e:9161:27dd:7f78:d242/tcp/4001
QmNTJyhCYcbv5GdnqtdEwTfJCgY6pV4PJiNTtAmuoxnQak (3)
/ip4/127.0.0.1/tcp/4001
/ip4/94.176.232.68/tcp/4001
/ip6/::1/tcp/4001
QmNTZy7TfXvsHczwwV3EYbxRZN5gthgicG9GiroD7C4ZrP (4)
/ip4/127.0.0.1/tcp/4001
/ip4/172.20.255.127/tcp/4001
/ip4/54.229.227.53/tcp/4001
/ip6/::1/tcp/4001
.
这些是本地节点在 swarm 中已知的地址,顶部的哈希是 peerId。
有了这些信息,您就可以连接到对等节点,比如这样:
$ ipfs swarm connect /ip4/114.91.202.180/tcp/34746/ipfs/QmfTgdg6GkqJtUrWAYo69GjcLrjQq9LjTjgW3KZ1ux1X6U
connect QmfTgdg6GkqJtUrWAYo69GjcLrjQq9LjTjgW3KZ1ux1X6U success
后面会介绍更多的关于 BitSwap 的信息。
休息一下吧
Pfew(?),到这里已经学习到了很多理论和干货,但是我们的 IPFS 白皮书的学习路程甚至还未过半! 因此,为了让它们更全面地被理解,并为了休息,放空大脑,去公园散散步,顺便听听这个播客:The Quiet Master of Cryptocurrency — Nick Szabo。 它到无处不在,但我发现它非常有趣。它把观察视角从比特级别拉远到一些到 “什么是钱?” 之类的(宏观的)东西。
强烈建议听一下,当你听完后,我们继续。
版本控制系统 - Git
白皮书关于版本控制系统的整个部分都复制在这里:
版本控制系统提供了对随时间变化的文件进行建模的设施,并有效地分发不同的版本。
流行版本控制系统 Git 提供了强大的 Merkle DAG 对象模型,以分布式友好的方式捕获对文件系统树的更改。
- 不可更改的对象表示文件(blob),目录(树)和更改(提交)。
- 通过加密 hash 对象的内容,让对象可寻址。
- 链接到其他对象是嵌入的,形成一个 Merkle DAG。这提供了有用的完整性和 workflow 属性。
- 大多数版本元数据(分支,标签等等)都只是指针引用,因此创建和更新的代价都很小。
- 版本改变只是更新引用或者添加对象。
- 分布式版本改变对其他用户而言只是转移对象和更新远程引用。
让我们逐行理解它:
Ad 1. 不可变对象表示文件(blob),目录(树)和更改(提交)。
Git 只添加数据。 所以 blob,树和提交是不可变的。 其中任何一个数据的最终版本是由特殊的引用决定的(见第 4 和第 5 点)。
Ad 2. 通过加密 hash 对象的内容,让对象可寻址。
在 git 中,引用它们时不使用文件或目录名。 Git 使用 SHA1 散列内容(或列出或提交)并在其数据库中使用这些散列值。这篇文章对于它的工作机制有很深刻的洞察: Git under the hood (从 “现在让我们来看看 Git 如何做到这一切” 这一节开始阅读)
Ad 3. 链接到其他对象是嵌入的,形成一个 Merkle DAG。这提供了有用的完整性和 workflow 属性。
哦,天哪,一个 Merkle DAG! 不用担心,它实际上并不像听起来那么可怕。
Merkle 树是二叉树,其中父级包含两个子节点的哈希值的拼接后内容的哈希值。 这解释了完整性属性的由来:数据块中的任何更改都会导致根节点发生更改。 只需要一点点元数据(叔节点和父节点,可以是不受信任的)和受信任的根节点,我们就可以验证块的有效性。
现在,Merkle DAG 与 Merkle 树不同。不同之处在于解释:Merkle DAG 和 JRFC 20 - Merkle DAG
简而言之:Merkle DAG 更通用,因为它不是二叉树而是图,任何节点都可以包含数据,而不仅仅是 Merkle 树中的叶子节点。
它仍然有点模糊,当我们看一下 IPFS Merkle DAG 时,我会再次讨论它。
Ad 4. 和 5. 大多数版本控制元数据(分支,标签等)只是指针引用,因此创建和更新成本低廉。版本更改仅更新引用或添加对象。
这里提供了一个可视化的方式观察 git 的运行机制: Git for Computer Scientists 这里可以看出分支,HEAD 和标签仅仅是对提交的引用。
Ad 6. 将版本更改分发给其他用户只是传输对象和更新远程引用。
这里说的是什么,我觉得没有必要解释:)
自我认证的文件系统 - SFS
这项技术用于实现 IPFS 的 IPNS 名称系统。它允许我们为远程文件系统生成地址,用户可以验证地址的有效性。
白皮书指出:
SFS 引入了一种用于构建自我认证文件系统的技术:使用以下方案寻址远程文件系统
/sfs/<Location>:<HostID>
其中 Location 是服务器网络地址,另外:
HostID = hash(public_key || Location)
因此,SFS 文件系统的命名实际上对其服务器进行认证。
这已经不言而喻了,我们将在下一篇中看到它的实际应用:Understanding the IPFS White Paper part 2
希望你将对这篇文章的看法通过推特给我 @pors。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。