路由层有两个主要功能:

  • 寻找节点
  • 寻找数据

https://github.com/libp2p/specs

1
git clone https://github.com/ngrinkevich/libp2p_example.git && cd libp2p_example && yarn && yarn start

运行一个节点,然后打开http://127.0.0.1:9090/,调出Console就能看到结果了。

文档,libp2p只是一个框架,需要添加模块才能实现功能。

1
git clone https://github.com/libp2p/js-libp2p && cd js-libp2p/

js-libp2p/examples下有一些例子,分别cd入然后安装。

1
yarn --registry https://registry.yarnpkg.com

libp2p-in-the-browser

1
2
3
cd libp2p-in-the-browser/1
yarn --registry https://registry.yarnpkg.com
yarn start

打开 http://127.0.0.1:9090/ ,发觉竟然还有节点,可见IPFS的先进性(。・∀・)ノ

尝试echo

dialer.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
async.parallel([
(cb) => PeerId.createFromJSON(require('./id-d'), cb),
(cb) => PeerId.createFromJSON(require('./id-l'), cb)
], (err, ids) => {
if (err) { throw err }

// Dialer
const dialerId = ids[0] // 此处是PeerId
const dialerPeerInfo = new PeerInfo(dialerId)
dialerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
const dialerNode = new Node({
peerInfo: dialerPeerInfo
})

// Peer to Dial
const listenerPeerInfo = new PeerInfo(ids[1])
const listenerId = ids[1]
const listenerMultiaddr = '/ip4/127.0.0.1/tcp/10333/p2p/' +
listenerId.toB58String()
listenerPeerInfo.multiaddrs.add(listenerMultiaddr)

https://www.npmjs.com/package/peer-id

由id、公钥、私钥创建了PeerId,再创建PeerInfo,再创建Node。

Multiaddr

https://github.com/multiformats/multiaddr

Multiaddr是一种表示地址的方式,区别于传统url。

传统url的问题很多,对机器不友善,不易解析。

Multiaddr支持任何协议,可读性良好。

有两种格式:可读格式和二进制格式。

通讯部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err }

console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0')

pull(
pull.values(['hey']),
conn,
pull.collect((err, data) => {
if (err) { throw err }
console.log('received echo:', data.toString())
})
)
})

pull(源,管道,目的地),数据经过三个函数的处理。hey发送后,pull.collect收集返回的数据。

1
listenerNode.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))

pull(conn, conn),把数据读出来又放回去,实现了回显功能。

节点的创建

libp2p只是胶水,用来打包模块组合节点。

libp2p-bundle.js

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
29
30
31
32
33
34
35
36
37
class Node extends libp2p {
constructor (_options) {
const defaults = {
modules: {
transport: [
TCP,
WS
],
streamMuxer: getMuxers(_options.muxer),
connEncryption: [ secio ],
peerDiscovery: [
MulticastDNS,
Bootstrap
],
dht: KadDHT
},
config: {
peerDiscovery: {
mdns: {
interval: 10000,
enabled: false
},
bootstrap: {
interval: 10000,
enabled: false,
list: _options.bootstrapList
}
},
dht: {
kBucketSize: 20
}
}
}

super(defaultsDeep(_options, defaults))
}
}

https://github.com/libp2p/js-libp2p

节点标识

IPFS使用节点公钥作为NodeID,节点首次连接时,交换公钥并验证公钥的哈希。

1
2
privateKey, publicKey := keygen()
nodeID := multihash(publicKey)