Merkledag是IPFS的核心,以Merkeldag为基础,可以建立一些复杂的数据结构:

  • git
  • bitcoin
  • unixfs

参考资料:

https://explore.ipld.io/#/explore/z8mWaJ4dRuSpBDDzCN773PsAYfbF3VERf ,这样就有直观感受了。

Routing层和Exchange层都是为Merkledag数据结构层做准备的,而那两层基本可以视为BitTorrent。

这层称为IPLD,Interplanetary Linked Data

Multiformats

Multiformat是一种自解释的数据格式,举一个例子,multihash。

multihash
0x 1114dc23ffefcd2feaef8036fda45e949afd86aae5d7
0x 11 = sha1 哈希函数代码
0x 14 = 160 bits 哈希摘要长度

比如,sha1函数不安全了,可以很方便地升级到更好的哈希函数。

Merkle dag 节点结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的数据结构是很灵活的,一个节点,只需要link的对象以内容编址、用上文方式编码即可。

data由IPFS上层应用控制,与IPFS关系不大。

列出一个节点的子节点:

1
2
3
4
5
> ipfs ls /XLZ1625Jjn7SubMDgEyeaynFuR84ginqvzb
XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x 189458 less
XLHBNmRQ5sJJrdMPuu48pzeyTtRo39tNDR5 19441 script
XLF4hwVHsVuZ78FZK6fozf8Jj9WEURMbCX4 5286 template
<object multihash> <object size> <link name>

路径

1
2
3
4
# format
/ipfs/<hash-of-object>/<name-path-to-object>
# example
/ipfs/XLYkgq61DYaQ8NhkcqyU7rLcnSa7dSHQ16x/foo.txt

通过遍历links解析路径。

对象层面的加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type EncryptedObject struct {
Object []bytes
// raw object data encrypted
Tag []bytes
// optional tag for encryption groups
}
type SignedObject struct {
Object []bytes
// raw object data signed
Signature []bytes
// hmac signature
PublicKey []multihash
// multihash identifying key
}

加密或者签名的IPFS对象被包含在另一个对象中。

若没有密钥,就不能遍历加密的对象了。

CID

z8mWaJHXieAVxxLagBpdaNWFEBKVWmMiE
base58btc - cidv1 - git-raw - sha1-160-dc23ffefcd2feaef8036fda45e949afd86aae5d7
multihash
0x 1114dc23ffefcd2feaef8036fda45e949afd86aae5d7
0x 11 = sha1
0x 14 = 160 bits

CID,Content identifier,内容标识符。

由三个部分组成:

  • Multibase - 以支持不同编码
  • Multicodec - 以支持不同序列化格式,codec指定数据如何转换成二进制格式。
  • Multihash

CID就是MerkleDag最基本的单元了,CID可以指向其他节点。

用CID组成一个树,每个节点都是一个文件,那么这个树·就是一个文件夹。

这样就是一个文件系统,查询文件时只需要遍历这个树。

实践

建一个文件夹,然后yarn init

1
yarn add ipfs-http-client cids --registry https://registry.yarnpkg.com

运行ipfs daemon .\ipfs.exe daemon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const ipfsClient = require('ipfs-http-client');
const CID = require('cids');

//Connecting ipfs instance to infura node. You can also use your local node.
const ipfs = new ipfsClient({ host: 'localhost', port: '5001', protocol: 'http' });

/*
Creating an IPLD format node:
ipfs.dag.put(dagNode, [options], [callback])
For more information see:
https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/DAG.md#ipfsdagputdagnode-options-callback
*/

ipfs.dag.put({ name: "vasa" }, { format: 'dag-cbor', hashAlg: 'sha2-256' }, (err, cid) => {
if (err) {
console.log("ERR\n", err);
}
console.log(cid)
//featching multihash buffer from cid object.
const multihash = cid.multihash;

//passing multihash buffer to CID object to convert multihash to a readable format
const cids = new CID(1, 'dag-cbor', multihash);

//Printing out the cid in a readable format
console.log(cids.toBaseEncodedString());
//zdpuAujL3noEMamveLPQWJPY6CYZHhHoskYQaZBvRbAfVwR8S
});

dag-cbor

https://github.com/ipld/specs/blob/master/block-layer/serialization-and-formats.md

1
2
3
4
5
6
7
8
9
10
11
12
13
┌────────────────────┐             ┌────────────────────┐
│ │ │ │
│ Serializer │ │ Deserializer │
│ │ │ │
└─────────┬──────────┘ └──────────^─────────┘
│ │
│ Sent to another peer │
│ │
┌─────────v──────────┐ ┌──────────┴─────────┐
│ │ │ │
│ Format ├─────────────> Format │
│ │ │ │
└────────────────────┘ └────────────────────┘

CBOR是IPFS的一种数据格式,代表着如何在结构化数据和二进制数据之间互转。