IPFS白皮书 Part 3

Bitswap & Merkle DAG

BitSwap Ledger 账本

BitSwap节点记录与其他节点的传输的花费。 节点纪录历史并避免篡改。 当连接时,BitSwap节点将交换帐目信息。 如果条目不匹配,将重新初始化账本,对应节点失去所有记录:信用&债务。 恶意节点可能故意“失去”帐本,希望清除债务来清除债务,但这样也将清零信用分。相邻节点可以将其视为不当行为,拒绝交换信息。

type Ledger struct {
owner NodeId
partner NodeId
bytes_sent int
bytes_recv int
timestamp Timestamp

节点可以选择保留历史纪录,尽管并不要求。 只有最新的帐本条目是有用的。 节点也可以清理历史账本。

BitSwap Specification

BitSwap节点要遵循以下协议

// 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);

简化的节点链接流程

1. 开启: 节点间交互账本,直到它们同意以上内容

2. 发送:节点间交换需要的数据列表和数据块

3. 关闭:关闭连接

4. 忽略:按照策略在一段时间内忽略某个节点

Peer.open(NodeId, Ledger) 开启

当节点连接时,一个节点需要使用已有的账本或者创建新账本。然后连同发送Open消息给对方。

收到Open消息时,节点将选择是否激活此链接。这取决于节点根据账本判断对方是否可信任:是否共享数据,余额是否很低。 在ignore_cooldown的时间内忽略请求,这样能有效发现问题所在,并且抵御攻击。

当激活一个连接时,节点将发送本地的账本和last_seen时间戳。然后将比较收到的账本,如果它们吻合,则开启链接。否则将初始化新的账本并发送。

Peer.send_want_list(WantList) 请求列表

在一下情景节点将向关联节点广播它的请求列表want_list:

  • 开启连接
  • 等待任意一段时间
  • 请求列表有变化
  • 收到一个新的数据块

当收到一个请求列表时,节点将存储下来,然后检查是否有需要的数据块。如果有的话,将按照BitSwap策略交换。

Peer.send_block(Block).

数据块的发送很显而易见,就是发送一些数据。当收到数据时,节点通过Multihash校验,然后返回一个确认信息。

当确认了数据块的正确传输,接受者将数据从需要列表need_list转移到持有列表have_list。双方都需要更新他们的账本来反应传输费用。

如果传输失败了,这代表着传输者不正常或正在攻击接收者。后者将在将来拒绝与其交换数据。BitSwap需要在一个可靠传输的环境下运行,所以在使用BitSwap传输前需要捕捉可能的错误。

Peer.close(Bool) 关闭

最终的关闭操作需要保证关闭不是误操作,否则需要立即再连接,保证数据传输的完整。

链接只能在以下的条件下被关闭:

  • 在silence_wait时间段,默认30秒,都没有收到任何数据,就发送 Peer.close(false)
  • 节点是活跃的,但是BitSwap被关闭,就发送 Peer.close(false)

在发送close 消息后,双方都关闭连接,清除状态。账本将被保存用于将来使用。

注意:不活跃节点间,除了Open消息其余都应该被忽略。若出现了不合理的消息,就需要重新初始化连接。

3. Object Merkle DAG 对象

DHT 和BitSwap帮助IPFS实现在P2P网络中的大规模可靠的数据交换。 在此基础上,IPFS使用Merkle DAG:一种有向无环图,其中对象之间的链接是嵌入在源中的目标的加密散列。Git使用了类似的结构。它带来了一下好处:

  • 按内容寻址:所有内容都有一个独特的包括连接的multi hash校验和
  • 防篡改:如果修改,通过检验和可以发现
  • 防冗余:所有保持完全相同内容的对象是平等的,只存储一份。 这对于索引对象特别有用,例如git tree和commits,或者是公共部分的数据。

IPFS对象结构

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 Merkle DAG是一种非常灵活的数据存储方式。 唯一的要求是(a)内容寻址,和(b)以上面的格式编码。 IPFS授予应用程序对数据字段的完全控制; 应用程序可以使用他们选择的任何自定义数据格式,对此IPFS可能无法限制。 独立的对象内连接链接表将允许IPFS:

  • 罗列所有的对象的引用
> ipfs ls /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb
XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x 189458 less
XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5 19441 script
XLF4hwVHsVuZ78FZK6fozf8Jj9WEURMbCX4 5286 template
<object multihash> <object size> <link name>
  • 通过解析字符串路径查找,如foo / bar / baz。 给定一个对象,IPFS将第一个部分的数据解析为DHT中的一个hash,根据链接获得第二个对象,并重复此过程的到下一个部分。 因此,无论数据格式如何,都可以通过遍历Merkle DAG得到所有数据。
  • 解析递归引用的所有对象:
ipfs refs --recursive /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb
XLLxhdgJcXzLbtsLRL1twCHA2NrURp4H38s
XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x
XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5
XLWVQDqxo9Km9zLyquoC9gAP8CL1gWnHZ7z

原数据和数据链接结构是在IPFS之上构建任意数据结构的必要组成部分。 虽然很容易理解Git如何在DAG上构建对象模型,但可以考虑一下这些这些潜在的解决方案:

  • 键值存储
  • 传统关系数据库
  • 链接数据triple存储
  • 链接文档发布系统
  • 链接通信平台
  • 加密模块链

这些都可以建立在IPFS Merkle DAG之上,可以使用IPFS作为更复杂应用系统的传输协议。

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.