refactor: add core modules to libp2p (#400)

* refactor: add js-libp2p-connection-manager to repo

Co-authored-by: David Dias <daviddias.p@gmail.com>
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Pedro Teixeira <i@pgte.me>
Co-authored-by: Vasco Santos <vasco.santos@ua.pt>

* test(conn-mgr): only run in node

* refactor: add js-libp2p-identify to repo

Co-authored-by: David Dias <daviddias.p@gmail.com>
Co-authored-by: Friedel Ziegelmayer <dignifiedquire@gmail.com>
Co-authored-by: Hugo Dias <hugomrdias@gmail.com>
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Maciej Krüger <mkg20001@gmail.com>
Co-authored-by: Richard Littauer <richard.littauer@gmail.com>
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
Co-authored-by: Yusef Napora <yusef@protocol.ai>
Co-authored-by: ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>

* refactor: add libp2p-pnet to repo

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>

* refactor: add libp2p-ping to repo

Co-authored-by: David Dias <daviddias.p@gmail.com>
Co-authored-by: Francisco Baio Dias <xicombd@gmail.com>
Co-authored-by: Friedel Ziegelmayer <dignifiedquire@gmail.com>
Co-authored-by: Hugo Dias <mail@hugodias.me>
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: João Antunes <j.goncalo.antunes@gmail.com>
Co-authored-by: Richard Littauer <richard.littauer@gmail.com>
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
Co-authored-by: Vasco Santos <vasco.santos@ua.pt>
Co-authored-by: ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>

* refactor: add libp2p-circuit to repo

Co-authored-by: David Dias <daviddias.p@gmail.com>
Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com>
Co-authored-by: Friedel Ziegelmayer <dignifiedquire@gmail.com>
Co-authored-by: Hugo Dias <mail@hugodias.me>
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Maciej Krüger <mkg20001@gmail.com>
Co-authored-by: Oli Evans <oli@tableflip.io>
Co-authored-by: Pedro Teixeira <i@pgte.me>
Co-authored-by: Vasco Santos <vasco.santos@ua.pt>
Co-authored-by: Victor Bjelkholm <victorbjelkholm@gmail.com>
Co-authored-by: Yusef Napora <yusef@napora.org>
Co-authored-by: dirkmc <dirk@mccormick.cx>

* test(switch): avoid using instanceof

* chore(switch): update bignumber dep

* refactor(circuit): clean up tests

* refactor(switch): consolidate get peer utils

* test(identify): do deep checks of addresses

* test(identify): bump timeout for identify test

* test(switch): tidy up limit dialer test

* refactor(switch): remove redundant circuit tests

* chore: add coverage script

* refactor(circuit): consolidate get peer info

* docs: reference original repositories in each sub readme

* docs: fix comment

* refactor: clean up sub package.json files and readmes
This commit is contained in:
Jacob Heun
2019-08-16 17:30:03 +02:00
committed by GitHub
parent d92306f222
commit b294301456
87 changed files with 5399 additions and 750 deletions

303
test/circuit/dialer.spec.js Normal file
View File

@@ -0,0 +1,303 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 5] */
'use strict'
const Dialer = require('../../src/circuit/circuit/dialer')
const nodes = require('./fixtures/nodes')
const Connection = require('interface-connection').Connection
const multiaddr = require('multiaddr')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream/pull')
const values = require('pull-stream/sources/values')
const asyncMap = require('pull-stream/throughs/async-map')
const pair = require('pull-pair/duplex')
const pb = require('pull-protocol-buffers')
const proto = require('../../src/circuit/protocol')
const utilsFactory = require('../../src/circuit/circuit/utils')
const sinon = require('sinon')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
describe(`dialer tests`, function () {
let dialer
beforeEach(() => {
dialer = sinon.createStubInstance(Dialer)
})
afterEach(() => {
sinon.restore()
})
describe(`.dial`, function () {
beforeEach(function () {
dialer.relayPeers = new Map()
dialer.relayPeers.set(nodes.node2.id, new Connection())
dialer.relayPeers.set(nodes.node3.id, new Connection())
dialer.dial.callThrough()
})
it(`fail on non circuit addr`, function () {
const dstMa = multiaddr(`/ipfs/${nodes.node4.id}`)
expect(() => dialer.dial(dstMa, (err) => {
err.to.match(/invalid circuit address/)
}))
})
it(`dial a peer`, function (done) {
const dstMa = multiaddr(`/p2p-circuit/ipfs/${nodes.node3.id}`)
dialer._dialPeer.callsFake(function (dstMa, relay, callback) {
return callback(null, dialer.relayPeers.get(nodes.node3.id))
})
dialer.dial(dstMa, (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.be.an.instanceOf(Connection)
done()
})
})
it(`dial a peer over the specified relay`, function (done) {
const dstMa = multiaddr(`/ipfs/${nodes.node3.id}/p2p-circuit/ipfs/${nodes.node4.id}`)
dialer._dialPeer.callsFake(function (dstMa, relay, callback) {
expect(relay.toString()).to.equal(`/ipfs/${nodes.node3.id}`)
return callback(null, new Connection())
})
dialer.dial(dstMa, (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.be.an.instanceOf(Connection)
done()
})
})
})
describe(`.canHop`, function () {
let fromConn = null
const peer = new PeerInfo(PeerId.createFromB58String('QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA'))
let p = null
beforeEach(function () {
p = pair()
fromConn = new Connection(p[0])
dialer.relayPeers = new Map()
dialer.relayConns = new Map()
dialer.utils = utilsFactory({})
dialer.canHop.callThrough()
dialer._dialRelayHelper.callThrough()
})
it(`should handle successful CAN_HOP`, (done) => {
dialer._dialRelay.callsFake((_, cb) => {
pull(
values([{
type: proto.CircuitRelay.type.HOP,
code: proto.CircuitRelay.Status.SUCCESS
}]),
pb.encode(proto.CircuitRelay),
p[1]
)
cb(null, fromConn)
})
dialer.canHop(peer, (err) => {
expect(err).to.not.exist()
expect(dialer.relayPeers.has(peer.id.toB58String())).to.be.ok()
done()
})
})
it(`should handle failed CAN_HOP`, function (done) {
dialer._dialRelay.callsFake((_, cb) => {
pull(
values([{
type: proto.CircuitRelay.type.HOP,
code: proto.CircuitRelay.Status.HOP_CANT_SPEAK_RELAY
}]),
pb.encode(proto.CircuitRelay),
p[1]
)
cb(null, fromConn)
})
dialer.canHop(peer, (err) => {
expect(err).to.exist()
expect(dialer.relayPeers.has(peer.id.toB58String())).not.to.be.ok()
done()
})
})
})
describe(`._dialPeer`, function () {
beforeEach(function () {
dialer.relayPeers = new Map()
dialer.relayPeers.set(nodes.node1.id, new Connection())
dialer.relayPeers.set(nodes.node2.id, new Connection())
dialer.relayPeers.set(nodes.node3.id, new Connection())
dialer._dialPeer.callThrough()
})
it(`should dial a peer over any relay`, function (done) {
const dstMa = multiaddr(`/ipfs/${nodes.node4.id}`)
dialer._negotiateRelay.callsFake(function (conn, dstMa, callback) {
if (conn === dialer.relayPeers.get(nodes.node3.id)) {
return callback(null, dialer.relayPeers.get(nodes.node3.id))
}
callback(new Error(`error`))
})
dialer._dialPeer(dstMa, (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.be.an.instanceOf(Connection)
expect(conn).to.deep.equal(dialer.relayPeers.get(nodes.node3.id))
done()
})
})
it(`should fail dialing a peer over any relay`, function (done) {
const dstMa = multiaddr(`/ipfs/${nodes.node4.id}`)
dialer._negotiateRelay.callsFake(function (conn, dstMa, callback) {
callback(new Error(`error`))
})
dialer._dialPeer(dstMa, (err, conn) => {
expect(conn).to.be.undefined()
expect(err).to.not.be.null()
expect(err).to.equal(`no relay peers were found or all relays failed to dial`)
done()
})
})
})
describe(`._negotiateRelay`, function () {
const dstMa = multiaddr(`/ipfs/${nodes.node4.id}`)
let conn = null
let peer = null
let p = null
before((done) => {
PeerId.createFromJSON(nodes.node4, (_, peerId) => {
PeerInfo.create(peerId, (err, peerInfo) => {
peer = peerInfo
peer.multiaddrs.add(`/p2p-circuit/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`)
done(err)
})
})
})
beforeEach(() => {
dialer.swarm = {
_peerInfo: peer
}
dialer.utils = utilsFactory({})
dialer.relayConns = new Map()
dialer._negotiateRelay.callThrough()
dialer._dialRelayHelper.callThrough()
peer = new PeerInfo(PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`))
p = pair()
conn = new Connection(p[1])
})
it(`should write the correct dst addr`, function (done) {
dialer._dialRelay.callsFake((_, cb) => {
pull(
p[0],
pb.decode(proto.CircuitRelay),
asyncMap((msg, cb) => {
expect(msg.dstPeer.addrs[0]).to.deep.equal(dstMa.buffer)
cb(null, {
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.SUCCESS
})
}),
pb.encode(proto.CircuitRelay),
p[0]
)
cb(null, conn)
})
dialer._negotiateRelay(peer, dstMa, done)
})
it(`should negotiate relay`, function (done) {
dialer._dialRelay.callsFake((_, cb) => {
pull(
p[0],
pb.decode(proto.CircuitRelay),
asyncMap((msg, cb) => {
expect(msg.dstPeer.addrs[0]).to.deep.equal(dstMa.buffer)
cb(null, {
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.SUCCESS
})
}),
pb.encode(proto.CircuitRelay),
p[0]
)
cb(null, conn)
})
dialer._negotiateRelay(peer, dstMa, (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.be.instanceOf(Connection)
done()
})
})
it(`should fail with an invalid peer id`, function (done) {
const dstMa = multiaddr('/ip4/127.0.0.1/tcp/4001')
dialer._dialRelay.callsFake((_, cb) => {
pull(
p[0],
pb.decode(proto.CircuitRelay),
asyncMap((msg, cb) => {
expect(msg.dstPeer.addrs[0]).to.deep.equal(dstMa.buffer)
cb(null, {
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.SUCCESS
})
}),
pb.encode(proto.CircuitRelay),
p[0]
)
cb(null, conn)
})
dialer._negotiateRelay(peer, dstMa, (err, conn) => {
expect(err).to.exist()
expect(conn).to.not.exist()
done()
})
})
it(`should handle failed relay negotiation`, function (done) {
dialer._dialRelay.callsFake((_, cb) => {
cb(null, conn)
pull(
values([{
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.MALFORMED_MESSAGE
}]),
pb.encode(proto.CircuitRelay),
p[0]
)
})
dialer._negotiateRelay(peer, dstMa, (err, conn) => {
expect(err).to.not.be.null()
expect(err).to.be.an.instanceOf(Error)
expect(err.message).to.be.equal(`Got 400 error code trying to dial over relay`)
done()
})
})
})
})

View File

@@ -0,0 +1,25 @@
'use strict'
exports.node1 = {
id: 'QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE',
privKey: 'CAASpwkwggSjAgEAAoIBAQDJwzJPar4nylKY71Mm5q2BOED8uPf1ILvIi15VwVZWqter6flnlii/RKEcBypPbFqJHHa56MvybgQgrFmHKwDjnJvq4jyOZfR+o/D/99Ft1p2FAEBjImSXAgNpK4YsbyV5r0Q1+Avcj++aWWlLu6enUrL9WGzeUkf0U5L6XwXEPRUQdEojAIQi241P1hyqXX5gKAZVGqcPtKb6p1db3fcXodkS1G6JR90TopJHCqTCECp3SB9c6LlG7KXU92sIHJBlhOEEzGkEI1pM1SWnNnW5VLEypU7P56ifzzp4QxPNiJeC+cmE5SrgR3cXP44iKOuNVRJwBpCh5oNYqECzgqJ9AgMBAAECggEBAJpCdqXHrAmKJCqv2HiGqCODGhTfax1s4IYNIJwaTOPIjUrwgfKUGSVb2H4wcEX3RyVLsO6lMcFyIg/FFlJFK9HavE8SmFAbXZqxx6I9HE+JZjf5IEFrW1Mlg+wWDejNNe7adSF6O79wATaWo+32VNGWZilTQTGd4UvJ1jc9DZCh8zZeNhm4C6exXD45gMB0HI1t2ZNl47scsBEE4rV+s7F7y8Yk/tIsf0wSI/H8KSXS5I9aFxr3Z9c3HOfbVwhnIfNUDqcFTeU5BnhByYNLJ4v9xGj7puidcabVXkt2zLmm/LHbKVeGzec9LW5D+KkuB/pKaslsCXN6bVlu+SbVr9UCgYEA7MXfzZw36vDyfn4LPCN0wgzz11uh3cm31QzOPlWpA7hIsL/eInpvc8wa9yBRC1sRk41CedPHn913MR6EJi0Ne6/B1QOmRYBUjr60VPRNdTXCAiLykjXg6+TZ+AKnxlUGK1hjTo8krhpWq7iD/JchVlLoqDAXGFHvSxN0H3WEUm8CgYEA2iWC9w1v+YHfT2PXcLxYde9EuLVkIS4TM7Kb0N3wr/4+K4xWjVXuaJJLJoAbihNAZw0Y+2s1PswDUEpSG0jXeNXLs6XcQxYSEAu/pFdvHFeg2BfwVQoeEFlWyTJR29uti9/APaXMo8FSVAPPR5lKZLStJDM9hEfAPfUaHyic39MCgYAKQbwjNQw7Ejr+/cjQzxxkt5jskFyftfhPs2FP0/ghYB9OANHHnpQraQEWCYFZQ5WsVac2jdUM+NQL/a1t1e/Klt+HscPHKPsAwAQh1f9w/2YrH4ZwjQL0VRKYKs1HyzEcOZT7tzm4jQ2KHNEi5Q0dpzPK7WJivFHoZ6xVHIsh4wKBgAQq20mk9BKsLHvzyFXbA0WdgI6WyIbpvmwqaVegJcz26nEiiTTCA3/z64OcxunoXD6bvXJwJeBBPX73LIJg7dzdGLsh3AdcEJRF5S9ajEDaW7RFIM4/FzvwuPu2/mFY3QPjDmUfGb23H7+DIx6XCxjJatVaNT6lsEJ+wDUALZ8JAoGAO0YJSEziA7y0dXPK5azkJUMJ5yaN+zRDmoBnEggza34rQW0s16NnIR0EBzKGwbpNyePlProv4dQEaLF1kboKsSYvV2rW2ftLVdNqBHEUYFRC9ofPctCxwM1YU21TI2/k1squ+swApg2EHMev2+WKd+jpVPIbCIvJ3AjiAKZtiGQ=',
pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJwzJPar4nylKY71Mm5q2BOED8uPf1ILvIi15VwVZWqter6flnlii/RKEcBypPbFqJHHa56MvybgQgrFmHKwDjnJvq4jyOZfR+o/D/99Ft1p2FAEBjImSXAgNpK4YsbyV5r0Q1+Avcj++aWWlLu6enUrL9WGzeUkf0U5L6XwXEPRUQdEojAIQi241P1hyqXX5gKAZVGqcPtKb6p1db3fcXodkS1G6JR90TopJHCqTCECp3SB9c6LlG7KXU92sIHJBlhOEEzGkEI1pM1SWnNnW5VLEypU7P56ifzzp4QxPNiJeC+cmE5SrgR3cXP44iKOuNVRJwBpCh5oNYqECzgqJ9AgMBAAE='
}
exports.node2 = {
id: 'QmYJjAri5soV8RbeQcHaYYcTAYTET17QTvcoFMyKvRDTXe',
privKey: 'CAASpgkwggSiAgEAAoIBAQDt7YgUeBQsoN/lrgo690mB7yEh8G9iXhZiDecgZCLRRSl3v2cH9w4WjhoW9erfnVbdoTqkCK+se8uK01ySi/ubQQDPcrjacXTa6wAuRTbCG/0bUR9RxKtxZZBS1HaY7L923ulgGDTiVaRQ3JQqhzmQkaU0ikNcluSGaw0kmhXP6JmcL+wndKgW5VD9etcp2Qlk8uUFC/GAO90cOAuER3wnI3ocHGm9on9zyb97g4TDzIfjSaTW4Wanmx2yVbURQxmCba16X3LT9IMPqQaGOzq3+EewMLeCESbUm/uJaJLdqWrWRK4oNzxcMgmUkzav+s476HdA9CRo72am+g3Vdq+lAgMBAAECggEAcByKD6MZVoIjnlVo6qoVUA1+3kAuK/rLrz5/1wp4QYXGaW+eO+mVENm6v3D3UJESGnLbb+nL5Ymbunmn2EHvuBNkL1wOcJgfiPxM5ICmscaAeHu8N0plwpQp8m28yIheG8Qj0az2VmQmfhfCFVwMquuGHgC8hwdu/Uu6MLIObx1xjtaGbY9kk7nzAeXHeJ4RDeuNN0QrYuQVKwrIz1NtPNDR/cli298ZXJcm+HEhBCIHVIYpAq6BHSuiXVqPGEOYWYXo+yVhEtDJ8BmNqlN1Y1s6bnfu/tFkKUN6iQQ46vYnQEGTGR9lg7J/c6tqfRs9FcywWb9J1SX6HxPO8184zQKBgQD6vDYl20UT4ZtrzhFfMyV/1QUqFM/TdwNuiOsIewHBol9o7aOjrxrrbYVa1HOxETyBjmFsW+iIfOVl61SG2HcU4CG+O2s9WBo4JdRlOm4YQ8/83xO3YfbXzuTx8BMCyP/i1uPIZTKQFFAN0HiL96r4L60xHoWB7tQsbZiEbIO/2wKBgQDy7HnkgVeTld6o0+sT84FYRUotjDB00oUWiSeGtj0pFC4yIxhMhD8QjKiWoJyJItcoCsQ/EncuuwwRtuXi83793lJQR1DBYd+TSPg0M8J1pw97fUIPi/FU+jHtrsx7Vn/7Bk9voictsYVLAfbi68tYdsZpAaYOWYMY9NUfVuAmfwKBgCYZDwk1hgt9TkZVK2KRvPLthTldrC5veQAEoeHJ/vxTFbg105V9d9Op8odYnLOc8NqmrbrvRCfpAlo4JcHPhliPrdDf6m2Jw4IgjWNMO4pIU4QSyUYmBoHIGBWC6wCTVf47tKSwa7xkub0/nfF2km3foKtD/fk+NtMBXBlS+7ndAoGAJo6GIlCtN82X07AfJcGGjB4jUetoXYJ0gUkvruAKARUk5+xOFQcAg33v3EiNz+5pu/9JesFRjWc+2Sjwf/8p7t10ry1Ckg8Yz2XLj22PteDYQj91VsZdfaFgf1s5NXJbSdqMjSltkoEUqP0c1JOcaOQhRdVvJ+PpPPLPSPQfC70CgYBvJE1I06s7BEM1DOli3VyfNaJDI4k9W2dCJOU6Bh2MNmbdRjM3xnpOKH5SqRlCz/oI9pn4dxgbX6WPg331MD9CNYy2tt5KBQRrSuDj8p4jlzMIpX36hsyTTrzYU6WWSIPz6jXW8IexXKvXEmr8TVb78ZPiQfbG012cdUhAJniNgg==',
pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDt7YgUeBQsoN/lrgo690mB7yEh8G9iXhZiDecgZCLRRSl3v2cH9w4WjhoW9erfnVbdoTqkCK+se8uK01ySi/ubQQDPcrjacXTa6wAuRTbCG/0bUR9RxKtxZZBS1HaY7L923ulgGDTiVaRQ3JQqhzmQkaU0ikNcluSGaw0kmhXP6JmcL+wndKgW5VD9etcp2Qlk8uUFC/GAO90cOAuER3wnI3ocHGm9on9zyb97g4TDzIfjSaTW4Wanmx2yVbURQxmCba16X3LT9IMPqQaGOzq3+EewMLeCESbUm/uJaJLdqWrWRK4oNzxcMgmUkzav+s476HdA9CRo72am+g3Vdq+lAgMBAAE='
}
exports.node3 = {
id: 'QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA',
privKey: 'CAASpwkwggSjAgEAAoIBAQDdnGp0X7Pix5dIawfyuffVryRDRS5JXdyjayKUkgikJLYoiijB5TakrFKhx1SDKpmVLxxqAGz8m5iA2cHwetIQXTZvdYx7XXxv332En3ji8TiGRUiEFM8KQ5WCJ5G7yw8R2pv/pYdnMrPd04QbtSCn0cFVCiiA2Zkl5KnwBo/lf+sVI/TEeiwmVD9nxi13qWgBTmCysqH8Ppyu8fq+bQgqRZSlalVDswyIhgWlepPkD0uYakJJhhOxY+2RlbNhGY0qjRyMTYou2uR/hfd6j8uR++WdB0v3+DYWG2Kc3sWa4BLYb5r4trvQGO1Iagnwuk3AVoi7PldsaInekzWEVljDAgMBAAECggEAXx0jE49/xXWkmJBXePYYSL5C8hxfIV4HtJvm251R2CFpjTy/AXk/Wq4bSRQkUaeXA1CVAWntXP3rFmJfurb8McnP80agZNJa9ikV1jYbzEt71yUlWosT0XPwV0xkYBVnAmKxUafZ1ZENYcfGi53RxjVgpP8XIzZBZOIfjcVDPVw9NAOzQmq4i3DJEz5xZAkaeSM8mn5ZFl1JMBUOgyOHB7d4BWd3zuLyvnn0/08HlsaSUl0mZa3f2Lm2NlsjOiNfMCJTOIT+xDEP9THm5n2cqieSjvtpAZzV4kcoD0rB8OsyHQlFAEXzkgELDr5dVXji0rrIdVz8stYAKGfi996OAQKBgQDuviV1sc+ClJQA59vqbBiKxWqcuCKMzvmL4Yk1e/AkQeRt+JX9kALWzBx65fFmHTj4Lus8AIQoiruPxa0thtqh/m3SlucWnrdaW410xbz3KqQWS7bx+0sFWZIEi4N+PESrIYhtVbFuRiabYgliqdSU9shxtXXnvfhjl+9quZltiwKBgQDtoUCKqrZbm0bmzLvpnKdNodg1lUHaKGgEvWgza2N1t3b/GE07iha2KO3hBDta3bdfIEEOagY8o13217D0VIGsYNKpiEGLEeNIjfcXBEqAKiTfa/sXUfTprpWBZQ/7ZS+eZIYtQjq14EHa7ifAby1v3yDrMIuxphz5JfKdXFgYqQKBgHr47FikPwu2tkmFJCyqgzWvnEufOQSoc7eOc1tePIKggiX2/mM+M4gqWJ0hJeeAM+D6YeZlKa2sUBItMxeZN7JrWGw5mEx5cl4TfFhipgP2LdDiLRiVZL4bte+rYQ67wm8XdatDkYIIlkhBBi6Q5dPZDcQsQNAedPvvvb2OXi4jAoGBAKp06FpP+L2fle2LYSRDlhNvDCvrpDA8mdkEkRGJb/AKKdb09LnH5WDH3VNy+KzGrHoVJfWUAmNPAOFHeYzabaZcUeEAd5utui7afytIjbSABrEpwRTKWneiH2aROzSnMdBZ5ZHjlz/N3Q+RlHxKg/piwTdUPHCzasch/HX6vsr5AoGAGvhCNPKyCwpu8Gg5GQdx0yN6ZPar9wieD345cLanDZWKkLRQbo4SfkfoS+PDfOLzDbWFdPRnWQ0qhdPm3D/N1YD/nudHqbeDlx0dj/6lEHmmPKFFO2kiNFEhn8DycNGbvWyVBKksacuRXav21+LvW+TatUkRMhi8fgRoypnbJjg=',
pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdnGp0X7Pix5dIawfyuffVryRDRS5JXdyjayKUkgikJLYoiijB5TakrFKhx1SDKpmVLxxqAGz8m5iA2cHwetIQXTZvdYx7XXxv332En3ji8TiGRUiEFM8KQ5WCJ5G7yw8R2pv/pYdnMrPd04QbtSCn0cFVCiiA2Zkl5KnwBo/lf+sVI/TEeiwmVD9nxi13qWgBTmCysqH8Ppyu8fq+bQgqRZSlalVDswyIhgWlepPkD0uYakJJhhOxY+2RlbNhGY0qjRyMTYou2uR/hfd6j8uR++WdB0v3+DYWG2Kc3sWa4BLYb5r4trvQGO1Iagnwuk3AVoi7PldsaInekzWEVljDAgMBAAE='
}
exports.node4 = {
id: 'QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy',
privKey: 'CAASqAkwggSkAgEAAoIBAQC6pg6LYWbY+49SOYdYap6RPqKqZxg80IXeo3hiTUbiGtTruxVYZpnz3UbernL9J9mwlXJGRUQJUKmXmi1yePTQiyclpH0KyPefaWLbpxJQdCBI1TPZpDWo2hutWSPqhKBU1QyH2FLKQPWLdxuIX1cNFPtIlSl5gCxN6oiDIwh7++kxNM1G+d5XgJX6iHLlLoNv3Wn6XYX+VtYdyZRFk8gYyT2BrISbxmsrSjSOodwUUzF8TYTjsqW6ksL2x0mrRm2cMM9evULktqwU+I8l9ulASDbFWBXUToXaZSL9M+Oq5JvZO0WIjPeYVpAgWladtayhdxg5dBv8aTbDaM5DZvyRAgMBAAECggEAR65YbZz1k6Vg0HI5kXI4/YzxicHYJBrtHqjnJdGJxHILjZCmzPFydJ5phkG29ZRlXRS381bMn0s0Jn3WsFzVoHWgjitSvl6aAsXFapgKR42hjHcc15vh47wH3xYZ3gobTRkZG96vRO+XnX0bvM7orqR9MM3gRMI9wZqt3LcKnhpiqSlyEZ3Zehu7ZZ8B+XcUw42H6ZTXgmg5mCFEjS/1rVt+EsdZl7Ll7jHigahPA6qMjyRiZB6T20qQ0FFYfmaNuRuuC6cWUXf8DOgnEjMB/Mi/Feoip9bTqNBrVYn2XeDxdMv5pDznNKXpalsMkZwx5FpNOMKnIMdQFyAGtkeQ9QKBgQD3rjTiulitpbbQBzF8VXeymtMJAbR1TAqNv2yXoowhL3JZaWICM7nXHjjsJa3UzJygbi8bO0KWrw7tY0nUbPy5SmHtNYhmUsEjiTjqEnNRrYN68tEKr0HlgX+9rArsjOcwucl2svFSfk+rTYDHU5neZkDDhu1QmnZm/pQI92Lo4wKBgQDA6wpMd53fmX9DhWegs3xelRStcqBTw1ucWVRyPgY1hO1cJ0oReYIXKEw9CHNLW0RHvnVM26kRnqCl+dTcg7dhLuqrckuyQyY1KcRYG1ryJnz3euucaSF2UCsZCHvFNV7Vz8dszUMUVCogWmroVP6HE/BoazUCNh25s/dNwE+i+wKBgEfa1WL1luaBzgCaJaQhk4FQY2sYgIcLEYDACTwQn0C9aBpCdXmYEhEzpmX0JHM5DTOJ48atsYrPrK/3/yJOoB8NUk2kGzc8SOYLWGSoB6aphRx1N2o3IBH6ONoJAH5R/nxnWehCz7oUBP74lCS/v0MDPUS8bzrUJQeKUd4sDxjrAoGBAIRO7rJA+1qF+J1DWi4ByxNHJXZLfh/UhPj23w628SU1dGDWZVsUvZ7KOXdGW2RcRLj7q5E5uXtnEoCillViVJtnRPSun7Gzkfm2Gn3ezQH0WZKVkA+mnpd5JgW2JsS69L6pEPnS0OWZT4b+3AFZgXL8vs2ucR2CJeLdxYdilHuPAoGBAPLCzBkAboXZZtvEWqzqtVNqdMrjLHihFrpg4TXSsk8+ZQZCVN+sRyTGTvBX8+Jvx4at6ClaSgT3eJ/412fEH6CHvrFXjUE9W9y6X0axxaT63y1OXmFiB/hU3vjLWZKZWSDGNS7St02fYri4tWmGtJDjYG1maLRhMSzcoj4fP1xz',
pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6pg6LYWbY+49SOYdYap6RPqKqZxg80IXeo3hiTUbiGtTruxVYZpnz3UbernL9J9mwlXJGRUQJUKmXmi1yePTQiyclpH0KyPefaWLbpxJQdCBI1TPZpDWo2hutWSPqhKBU1QyH2FLKQPWLdxuIX1cNFPtIlSl5gCxN6oiDIwh7++kxNM1G+d5XgJX6iHLlLoNv3Wn6XYX+VtYdyZRFk8gYyT2BrISbxmsrSjSOodwUUzF8TYTjsqW6ksL2x0mrRm2cMM9evULktqwU+I8l9ulASDbFWBXUToXaZSL9M+Oq5JvZO0WIjPeYVpAgWladtayhdxg5dBv8aTbDaM5DZvyRAgMBAAE='
}

View File

@@ -0,0 +1,22 @@
'use strict'
const Libp2p = require('../../../src')
const secio = require('libp2p-secio')
class TestNode extends Libp2p {
constructor (peerInfo, transports, muxer, options) {
options = options || {}
const modules = {
transport: transports,
connection: {
muxer: [muxer],
crypto: options.isCrypto ? [secio] : null
},
discovery: []
}
super(modules, peerInfo, null, options)
}
}
module.exports = TestNode

View File

@@ -0,0 +1,78 @@
'use strict'
const TestNode = require('./test-node')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const eachAsync = require('async/each')
exports.createNodes = function createNodes (configNodes, callback) {
const nodes = {}
eachAsync(Object.keys(configNodes), (key, cb1) => {
const config = configNodes[key]
const setup = (err, peer) => {
if (err) {
callback(err)
}
eachAsync(config.addrs, (addr, cb2) => {
peer.multiaddrs.add(addr)
cb2()
}, (err) => {
if (err) {
return callback(err)
}
nodes[key] = new TestNode(peer, config.transports, config.muxer, config.config)
cb1()
})
}
if (config.id) {
PeerId.createFromJSON(config.id, (err, peerId) => {
if (err) return callback(err)
PeerInfo.create(peerId, setup)
})
} else {
PeerInfo.create(setup)
}
}, (err) => {
if (err) {
return callback(err)
}
startNodes(nodes, (err) => {
if (err) {
callback(err)
}
callback(null, nodes)
})
})
}
function startNodes (nodes, callback) {
eachAsync(Object.keys(nodes),
(key, cb) => {
nodes[key].start(cb)
},
(err) => {
if (err) {
return callback(err)
}
callback(null)
})
}
exports.stopNodes = function stopNodes (nodes, callback) {
eachAsync(Object.keys(nodes),
(key, cb) => {
nodes[key].stop(cb)
},
(err) => {
if (err) {
return callback(err)
}
callback()
})
}

433
test/circuit/hop.spec.js Normal file
View File

@@ -0,0 +1,433 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 5] */
'use strict'
const Hop = require('../../src/circuit/circuit/hop')
const nodes = require('./fixtures/nodes')
const Connection = require('interface-connection').Connection
const handshake = require('pull-handshake')
const waterfall = require('async/waterfall')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const pull = require('pull-stream/pull')
const values = require('pull-stream/sources/values')
const collect = require('pull-stream/sinks/collect')
const lp = require('pull-length-prefixed')
const proto = require('../../src/circuit/protocol')
const StreamHandler = require('../../src/circuit/circuit/stream-handler')
const sinon = require('sinon')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
describe('relay', () => {
describe(`.handle`, () => {
let relay
let swarm
let fromConn
let stream
let shake
beforeEach((done) => {
stream = handshake({ timeout: 1000 * 60 })
shake = stream.handshake
fromConn = new Connection(stream)
const peerInfo = new PeerInfo(PeerId.createFromB58String('QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA'))
fromConn.setPeerInfo(peerInfo)
const peers = {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE:
new PeerInfo(PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`)),
QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA:
new PeerInfo(PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`)),
QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy:
new PeerInfo(PeerId.createFromB58String(`QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`))
}
Object.keys(peers).forEach((key) => { peers[key]._connectedMultiaddr = true }) // make it truthy
waterfall([
(cb) => PeerId.createFromJSON(nodes.node4, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peer, cb) => {
peer.multiaddrs.add('/p2p-circuit/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE')
swarm = {
_peerInfo: peer,
conns: {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE: new Connection(),
QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA: new Connection(),
QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy: new Connection()
},
_peerBook: {
get: (peer) => {
if (!peers[peer]) {
throw new Error()
}
return peers[peer]
}
}
}
cb()
}
], () => {
relay = new Hop(swarm, { enabled: true })
relay._circuit = sinon.stub()
relay._circuit.callsArgWith(2, null, new Connection())
done()
})
})
afterEach(() => {
relay._circuit.reset()
})
it(`should handle a valid circuit request`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).id,
addrs: [multiaddr(`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).buffer]
},
dstPeer: {
id: PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).id,
addrs: [multiaddr(`/ipfs/QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).buffer]
}
}
relay.on('circuit:success', () => {
expect(relay._circuit.calledWith(sinon.match.any, relayMsg)).to.be.ok()
done()
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
it(`should handle a request to passive circuit`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).id,
addrs: [multiaddr(`/ipfs/QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).buffer]
},
dstPeer: {
id: PeerId.createFromB58String(`QmYJjAri5soV8RbeQcHaYYcTAYTET17QTvcoFMyKvRDTXe`).id,
addrs: [multiaddr(`/ipfs/QmYJjAri5soV8RbeQcHaYYcTAYTET17QTvcoFMyKvRDTXe`).buffer]
}
}
relay.active = false
lp.decodeFromReader(
shake,
(err, msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(msg)
expect(response.code).to.equal(proto.CircuitRelay.Status.HOP_NO_CONN_TO_DST)
expect(response.type).to.equal(proto.CircuitRelay.Type.STATUS)
done()
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
it(`should handle a request to active circuit`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).id,
addrs: [multiaddr(`/ipfs/QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).buffer]
},
dstPeer: {
id: PeerId.createFromB58String(`QmYJjAri5soV8RbeQcHaYYcTAYTET17QTvcoFMyKvRDTXe`).id,
addrs: [multiaddr(`/ipfs/QmYJjAri5soV8RbeQcHaYYcTAYTET17QTvcoFMyKvRDTXe`).buffer]
}
}
relay.active = true
relay.on('circuit:success', () => {
expect(relay._circuit.calledWith(sinon.match.any, relayMsg)).to.be.ok()
done()
})
relay.on('circuit:error', (err) => {
done(err)
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
it(`not dial to self`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).id,
addrs: [multiaddr(`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).buffer]
},
dstPeer: {
id: PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).id,
addrs: [multiaddr(`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).buffer]
}
}
lp.decodeFromReader(
shake,
(err, msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(msg)
expect(response.code).to.equal(proto.CircuitRelay.Status.HOP_CANT_RELAY_TO_SELF)
expect(response.type).to.equal(proto.CircuitRelay.Type.STATUS)
done()
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
it(`fail on invalid src address`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: `sdfkjsdnfkjdsb`,
addrs: [`sdfkjsdnfkjdsb`]
},
dstPeer: {
id: PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).id,
addrs: [multiaddr(`/ipfs/QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).buffer]
}
}
lp.decodeFromReader(
shake,
(err, msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(msg)
expect(response.code).to.equal(proto.CircuitRelay.Status.HOP_SRC_MULTIADDR_INVALID)
expect(response.type).to.equal(proto.CircuitRelay.Type.STATUS)
done()
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
it(`fail on invalid dst address`, (done) => {
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).id,
addrs: [multiaddr(`/ipfs/QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`).buffer]
},
dstPeer: {
id: PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).id,
addrs: [`sdfkjsdnfkjdsb`]
}
}
lp.decodeFromReader(
shake,
(err, msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(msg)
expect(response.code).to.equal(proto.CircuitRelay.Status.HOP_DST_MULTIADDR_INVALID)
expect(response.type).to.equal(proto.CircuitRelay.Type.STATUS)
done()
})
relay.handle(relayMsg, new StreamHandler(fromConn))
})
})
describe(`._circuit`, () => {
let relay
let swarm
let srcConn
let dstConn
let srcStream
let dstStream
let srcShake
let dstShake
before((done) => {
srcStream = handshake({ timeout: 1000 * 60 })
srcShake = srcStream.handshake
srcConn = new Connection(srcStream)
dstStream = handshake({ timeout: 1000 * 60 })
dstShake = dstStream.handshake
dstConn = new Connection(dstStream)
const peerInfo = new PeerInfo(PeerId.createFromB58String('QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA'))
srcConn.setPeerInfo(peerInfo)
const peers = {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE:
new PeerInfo(PeerId.createFromB58String(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`)),
QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA:
new PeerInfo(PeerId.createFromB58String(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`)),
QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy:
new PeerInfo(PeerId.createFromB58String(`QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`))
}
Object.keys(peers).forEach((key) => { peers[key]._connectedMultiaddr = true }) // make it truthy
waterfall([
(cb) => PeerId.createFromJSON(nodes.node4, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peer, cb) => {
peer.multiaddrs.add('/p2p-circuit/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE')
swarm = {
_peerInfo: peer,
conns: {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE: new Connection(),
QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA: new Connection(),
QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy: new Connection()
},
_peerBook: {
get: (peer) => {
if (!peers[peer]) {
throw new Error()
}
return peers[peer]
}
}
}
cb()
}
], () => {
relay = new Hop(swarm, { enabled: true })
relay._dialPeer = sinon.stub()
relay._dialPeer.callsArgWith(1, null, dstConn)
done()
})
})
after(() => relay._dialPeer.reset())
describe('should correctly dial destination node', () => {
const msg = {
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: Buffer.from(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`),
addrs: [Buffer.from(`dsfsdfsdf`)]
},
dstPeer: {
id: Buffer.from(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`),
addrs: [Buffer.from(`sdflksdfndsklfnlkdf`)]
}
}
before(() => {
relay._circuit(
new StreamHandler(srcConn),
msg,
(err) => {
expect(err).to.not.exist()
})
})
it('should respond with SUCCESS to source node', (done) => {
lp.decodeFromReader(
srcShake,
(err, msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(msg)
expect(response.type).to.equal(proto.CircuitRelay.Type.STATUS)
expect(response.code).to.equal(proto.CircuitRelay.Status.SUCCESS)
done()
})
})
it('should send STOP message to destination node', (done) => {
lp.decodeFromReader(
dstShake,
(err, _msg) => {
expect(err).to.not.exist()
const response = proto.CircuitRelay.decode(_msg)
expect(response.type).to.deep.equal(msg.type)
expect(response.srcPeer).to.deep.equal(msg.srcPeer)
expect(response.dstPeer).to.deep.equal(msg.dstPeer)
done()
})
})
it('should create circuit', (done) => {
pull(
values([proto.CircuitRelay.encode({
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.SUCCESS
})]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => dstShake.write(e))
pull(
values([Buffer.from('hello')]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => srcShake.write(e))
lp.decodeFromReader(
dstShake,
(err, _msg) => {
expect(err).to.not.exist()
expect(_msg.toString()).to.equal('hello')
done()
})
})
)
})
)
})
})
describe('should fail creating circuit', () => {
const msg = {
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: Buffer.from(`QmQWqGdndSpAkxfk8iyiJyz3XXGkrDNujvc8vEst3baubA`),
addrs: [Buffer.from(`dsfsdfsdf`)]
},
dstPeer: {
id: Buffer.from(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`),
addrs: [Buffer.from(`sdflksdfndsklfnlkdf`)]
}
}
it('should not create circuit', (done) => {
relay._circuit(
new StreamHandler(srcConn),
msg,
(err) => {
expect(err).to.exist()
expect(err).to.match(/Unable to create circuit!/)
done()
})
pull(
values([proto.CircuitRelay.encode({
type: proto.CircuitRelay.Type.STATUS,
code: proto.CircuitRelay.Status.STOP_RELAY_REFUSED
})]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => dstShake.write(e))
})
)
})
})
})
})

View File

@@ -0,0 +1,292 @@
/* eslint-env mocha */
'use strict'
const Listener = require('../../src/circuit/listener')
const nodes = require('./fixtures/nodes')
const waterfall = require('async/waterfall')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const handshake = require('pull-handshake')
const Connection = require('interface-connection').Connection
const proto = require('../../src/circuit/protocol')
const lp = require('pull-length-prefixed')
const pull = require('pull-stream/pull')
const values = require('pull-stream/sources/values')
const collect = require('pull-stream/sinks/collect')
const multicodec = require('../../src/circuit/multicodec')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const sinon = require('sinon')
describe('listener', function () {
describe(`listen`, function () {
let swarm = null
let handlerSpy = null
let listener = null
let stream = null
let shake = null
let conn = null
beforeEach(function (done) {
stream = handshake({ timeout: 1000 * 60 })
shake = stream.handshake
conn = new Connection(stream)
conn.setPeerInfo(new PeerInfo(PeerId
.createFromB58String('QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE')))
waterfall([
(cb) => PeerId.createFromJSON(nodes.node4, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peer, cb) => {
swarm = {
_peerInfo: peer,
handle: sinon.spy((proto, h) => {
handlerSpy = sinon.spy(h)
}),
conns: {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE: new Connection()
}
}
listener = Listener(swarm, {}, () => {})
listener.listen()
cb()
}
], done)
})
afterEach(() => {
listener = null
})
it(`should handle HOP`, function (done) {
handlerSpy(multicodec.relay, conn)
const relayMsg = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`]
}
}
listener.hopHandler.handle = (message, conn) => {
expect(message.type).to.equal(proto.CircuitRelay.Type.HOP)
expect(message.srcPeer.id.toString()).to.equal(relayMsg.srcPeer.id)
expect(message.srcPeer.addrs[0].toString()).to.equal(relayMsg.srcPeer.addrs[0])
expect(message.dstPeer.id.toString()).to.equal(relayMsg.dstPeer.id)
expect(message.dstPeer.addrs[0].toString()).to.equal(relayMsg.dstPeer.addrs[0])
done()
}
pull(
values([proto.CircuitRelay.encode(relayMsg)]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => shake.write(e))
})
)
})
it(`should handle STOP`, function (done) {
handlerSpy(multicodec.relay, conn)
const relayMsg = {
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`]
}
}
listener.stopHandler.handle = (message, conn) => {
expect(message.type).to.equal(proto.CircuitRelay.Type.STOP)
expect(message.srcPeer.id.toString()).to.equal(relayMsg.srcPeer.id)
expect(message.srcPeer.addrs[0].toString()).to.equal(relayMsg.srcPeer.addrs[0])
expect(message.dstPeer.id.toString()).to.equal(relayMsg.dstPeer.id)
expect(message.dstPeer.addrs[0].toString()).to.equal(relayMsg.dstPeer.addrs[0])
done()
}
pull(
values([proto.CircuitRelay.encode(relayMsg)]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => shake.write(e))
})
)
})
it(`should emit 'connection'`, function (done) {
handlerSpy(multicodec.relay, conn)
const relayMsg = {
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`]
}
}
listener.stopHandler.handle = (message, sh) => {
const newConn = new Connection(sh.rest())
listener.stopHandler.emit('connection', newConn)
}
listener.on('connection', (conn) => {
expect(conn).to.be.instanceof(Connection)
done()
})
pull(
values([proto.CircuitRelay.encode(relayMsg)]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => shake.write(e))
})
)
})
it(`should handle CAN_HOP`, function (done) {
handlerSpy(multicodec.relay, conn)
const relayMsg = {
type: proto.CircuitRelay.Type.CAN_HOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`]
}
}
listener.hopHandler.handle = (message, conn) => {
expect(message.type).to.equal(proto.CircuitRelay.Type.CAN_HOP)
expect(message.srcPeer.id.toString()).to.equal(relayMsg.srcPeer.id)
expect(message.srcPeer.addrs[0].toString()).to.equal(relayMsg.srcPeer.addrs[0])
expect(message.dstPeer.id.toString()).to.equal(relayMsg.dstPeer.id)
expect(message.dstPeer.addrs[0].toString()).to.equal(relayMsg.dstPeer.addrs[0])
done()
}
pull(
values([proto.CircuitRelay.encode(relayMsg)]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => shake.write(e))
})
)
})
it(`should handle invalid message correctly`, function (done) {
handlerSpy(multicodec.relay, conn)
const relayMsg = {
type: 100000,
srcPeer: {
id: Buffer.from(`QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`),
addrs: [multiaddr(`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`).buffer]
},
dstPeer: {
id: Buffer.from(`QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`),
addrs: [multiaddr(`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`).buffer]
}
}
pull(
values([Buffer.from([relayMsg])]),
lp.encode(),
collect((err, encoded) => {
expect(err).to.not.exist()
encoded.forEach((e) => shake.write(e))
}),
lp.decodeFromReader(shake, { maxLength: this.maxLength }, (err, msg) => {
expect(err).to.not.exist()
expect(proto.CircuitRelay.decode(msg).type).to.equal(proto.CircuitRelay.Type.STATUS)
expect(proto.CircuitRelay.decode(msg).code).to.equal(proto.CircuitRelay.Status.MALFORMED_MESSAGE)
done()
})
)
})
})
describe(`getAddrs`, function () {
let swarm = null
let listener = null
let peerInfo = null
beforeEach(function (done) {
waterfall([
(cb) => PeerId.createFromJSON(nodes.node4, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peer, cb) => {
swarm = {
_peerInfo: peer
}
peerInfo = peer
listener = Listener(swarm, {}, () => {})
cb()
}
], done)
})
afterEach(() => {
peerInfo = null
})
it(`should return correct addrs`, function () {
peerInfo.multiaddrs.add(`/ip4/0.0.0.0/tcp/4002`)
peerInfo.multiaddrs.add(`/ip4/127.0.0.1/tcp/4003/ws`)
listener.getAddrs((err, addrs) => {
expect(err).to.not.exist()
expect(addrs).to.deep.equal([
multiaddr(`/p2p-circuit/ip4/0.0.0.0/tcp/4002/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`),
multiaddr(`/p2p-circuit/ip4/127.0.0.1/tcp/4003/ws/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`)])
})
})
it(`don't return default addrs in an explicit p2p-circuit addres`, function () {
peerInfo.multiaddrs.add(`/ip4/127.0.0.1/tcp/4003/ws`)
peerInfo.multiaddrs.add(`/p2p-circuit/ip4/0.0.0.0/tcp/4002`)
listener.getAddrs((err, addrs) => {
expect(err).to.not.exist()
expect(addrs[0]
.toString())
.to.equal(`/p2p-circuit/ip4/0.0.0.0/tcp/4002/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`)
})
})
})
})

View File

@@ -0,0 +1,50 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const multiaddr = require('multiaddr')
const proto = require('../../src/circuit/protocol')
describe('protocol', function () {
let msgObject = null
let message = null
before(() => {
msgObject = {
type: proto.CircuitRelay.Type.HOP,
srcPeer: {
id: Buffer.from('QmSource'),
addrs: [
multiaddr('/p2p-circuit/ipfs/QmSource').buffer,
multiaddr('/p2p-circuit/ip4/0.0.0.0/tcp/9000/ipfs/QmSource').buffer,
multiaddr('/ip4/0.0.0.0/tcp/9000/ipfs/QmSource').buffer
]
},
dstPeer: {
id: Buffer.from('QmDest'),
addrs: [
multiaddr('/p2p-circuit/ipfs/QmDest').buffer,
multiaddr('/p2p-circuit/ip4/1.1.1.1/tcp/9000/ipfs/QmDest').buffer,
multiaddr('/ip4/1.1.1.1/tcp/9000/ipfs/QmDest').buffer
]
}
}
const buff = proto.CircuitRelay.encode(msgObject)
message = proto.CircuitRelay.decode(buff)
})
it(`should source and dest`, () => {
expect(message.srcPeer).to.deep.equal(msgObject.srcPeer)
expect(message.dstPeer).to.deep.equal(msgObject.dstPeer)
})
it(`should encode message`, () => {
expect(message.message).to.deep.equal(msgObject.message)
})
})

85
test/circuit/stop.spec.js Normal file
View File

@@ -0,0 +1,85 @@
/* eslint-env mocha */
'use strict'
const Stop = require('../../src/circuit/circuit/stop')
const nodes = require('./fixtures/nodes')
const Connection = require('interface-connection').Connection
const handshake = require('pull-handshake')
const waterfall = require('async/waterfall')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const StreamHandler = require('../../src/circuit/circuit/stream-handler')
const proto = require('../../src/circuit/protocol')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
describe('stop', function () {
describe(`handle relayed connections`, function () {
let stopHandler
let swarm
let conn
let stream
beforeEach(function (done) {
stream = handshake({ timeout: 1000 * 60 })
conn = new Connection(stream)
const peerId = PeerId.createFromB58String('QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE')
conn.setPeerInfo(new PeerInfo(peerId))
waterfall([
(cb) => PeerId.createFromJSON(nodes.node4, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peer, cb) => {
peer.multiaddrs.add('/p2p-circuit/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE')
swarm = {
_peerInfo: peer,
conns: {
QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE: new Connection()
}
}
stopHandler = new Stop(swarm)
cb()
}
], done)
})
it(`handle request with a valid multiaddr`, function (done) {
stopHandler.handle({
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`/ipfs/QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`/ipfs/QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`]
}
}, new StreamHandler(conn), (conn) => { // multistream handler doesn't expect errors...
expect(conn).to.be.instanceOf(Connection)
done()
})
})
it(`handle request with invalid multiaddr`, function (done) {
stopHandler.handle({
type: proto.CircuitRelay.Type.STOP,
srcPeer: {
id: `QmSswe1dCFRepmhjAMR5VfHeokGLcvVggkuDJm7RMfJSrE`,
addrs: [`dsfsdfsdf`]
},
dstPeer: {
id: `QmQvM2mpqkjyXWbTHSUidUAWN26GgdMphTh9iGDdjgVXCy`,
addrs: [`sdflksdfndsklfnlkdf`]
}
}, new StreamHandler(conn), (conn) => {
expect(conn).to.not.exist()
done()
})
})
})
})

View File

@@ -0,0 +1,19 @@
/* eslint-env mocha */
'use strict'
const Prepare = require('./utils/prepare')
describe('default', function () {
const prepare = Prepare(3, { pollInterval: 1000 })
before(prepare.before)
after(prepare.after)
it('does not kick out any peer', (done) => {
prepare.connManagers().forEach((connManager) => {
connManager.on('disconnected', () => {
throw new Error('should not have disconnected')
})
})
setTimeout(done, 1900)
})
})

View File

@@ -0,0 +1,36 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxData', function () {
const prepare = Prepare(PEER_COUNT, {
maxData: 100,
minPeers: 1
})
before(prepare.create)
after(prepare.after)
it('kicks out peer after maxData reached', function (done) {
this.timeout(10000)
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,59 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxEventLoopDelay', function () {
const prepare = Prepare(PEER_COUNT, [{
pollInterval: 1000,
maxEventLoopDelay: 5,
minPeers: 1
}])
before(prepare.create)
after(prepare.after)
it('kicks out peer after maxEventLoopDelay reached', function (done) {
this.timeout(10000)
let stopped = false
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
stopped = true
done()
})
prepare.tryConnectAll((err) => {
expect(err).to.not.exist()
makeDelay()
})
function makeDelay () {
let sum = 0
for (let i = 0; i < 1000000; i++) {
sum += Math.random()
}
debug(sum)
if (!stopped) {
setTimeout(makeDelay, 0)
}
}
})
})
function debug (what) {
if (what === 0) {
// never true but the compiler doesn't know that
throw new Error('something went wrong')
}
}

View File

@@ -0,0 +1,37 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxPeers', function () {
const prepare = Prepare(PEER_COUNT, [{
maxPeersPerProtocol: {
tcp: 1
}
}])
before(prepare.create)
after(prepare.after)
it('kicks out peers in excess', function (done) {
this.timeout(10000)
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,35 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxPeers', function () {
const prepare = Prepare(PEER_COUNT, [{
maxPeers: 1
}])
before(prepare.create)
after(prepare.after)
it('kicks out peers in excess', function (done) {
this.timeout(10000)
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err, eachNodeConnections) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,36 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxReceivedData', function () {
const prepare = Prepare(PEER_COUNT, {
maxReceivedData: 50,
minPeers: 1
})
before(prepare.create)
after(prepare.after)
it('kicks out peer after maxReceivedData reached', function (done) {
this.timeout(10000)
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err, eachNodeConnections) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,36 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('maxSentData', function () {
const prepare = Prepare(PEER_COUNT, [{
maxSentData: 50,
minPeers: 1
}])
before(prepare.create)
after(prepare.after)
it('kicks out peer after maxSentData reached', function (done) {
this.timeout(10000)
let disconnects = 0
const manager = prepare.connManagers()[0]
manager.on('disconnected', () => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err, eachNodeConnections) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,10 @@
'use strict'
require('./default')
require('./max-data')
require('./max-event-loop-delay')
require('./max-peer-per-protocol')
require('./max-peers')
require('./max-received-data')
require('./max-sent-data')
require('./set-peer-value')

View File

@@ -0,0 +1,44 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const Prepare = require('./utils/prepare')
const PEER_COUNT = 3
describe('setPeerValue', function () {
const prepare = Prepare(PEER_COUNT, [{
maxPeers: 1,
defaultPeerValue: 0
}])
before(prepare.create)
after(prepare.after)
it('kicks out lower valued peer first', function (done) {
let disconnects = 0
let firstConnectedPeer
const manager = prepare.connManagers()[0]
manager.once('connected', (peerId) => {
if (!firstConnectedPeer) {
firstConnectedPeer = peerId
manager.setPeerValue(peerId, 1)
}
})
manager.on('disconnected', (peerId) => {
disconnects++
expect(disconnects).to.be.most(PEER_COUNT - 2)
expect(peerId).to.not.be.equal(firstConnectedPeer)
manager.removeAllListeners('disconnected')
done()
})
prepare.tryConnectAll((err) => {
expect(err).to.not.exist()
})
})
})

View File

@@ -0,0 +1,17 @@
'use strict'
const eachSeries = require('async/eachSeries')
module.exports = (nodes, callback) => {
eachSeries(
nodes,
(node, cb) => {
eachSeries(
nodes.filter(n => node !== n),
(otherNode, cb) => node.dial(otherNode.peerInfo, cb),
cb
)
},
callback
)
}

View File

@@ -0,0 +1,50 @@
'use strict'
const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio')
const libp2p = require('../../../src')
const waterfall = require('async/waterfall')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const ConnManager = require('libp2p-connection-manager')
class Node extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [TCP],
streamMuxer: [Multiplex],
connEncryption: [SECIO]
}
super({
peerInfo,
modules,
config: {
peerDiscovery: {
autoDial: false
}
}
})
}
}
function createLibp2pNode (options, callback) {
let node
waterfall([
(cb) => PeerId.create({ bits: 1024 }, cb),
(id, cb) => PeerInfo.create(id, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/0')
node = new Node(peerInfo)
// Replace the connection manager so we use source code instead of dep code
node.connectionManager = new ConnManager(node, options)
node.start(cb)
}
], (err) => callback(err, node))
}
exports = module.exports = createLibp2pNode
exports.bundle = Node

View File

@@ -0,0 +1,83 @@
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const series = require('async/series')
const each = require('async/each')
const createLibp2pNode = require('./create-libp2p-node')
const connectAll = require('./connect-all')
const tryConnectAll = require('./try-connect-all')
module.exports = (count, options) => {
let nodes
if (!Array.isArray(options)) {
const opts = options
options = []
for (let n = 0; n < count; n++) {
options[n] = opts
}
}
const create = (done) => {
const tasks = []
for (let i = 0; i < count; i++) {
tasks.push((cb) => createLibp2pNode(options.shift() || {}, cb))
}
series(tasks, (err, things) => {
if (!err) {
nodes = things
expect(things.length).to.equal(count)
}
done(err)
})
}
const connect = function (done) {
if (this && this.timeout) {
this.timeout(10000)
}
connectAll(nodes, done)
}
const tryConnectAllFn = function (done) {
if (this && this.timeout) {
this.timeout(10000)
}
tryConnectAll(nodes, done)
}
const before = (done) => {
if (this && this.timeout) {
this.timeout(10000)
}
series([create, connect], done)
}
const after = function (done) {
if (this && this.timeout) {
this.timeout(10000)
}
if (!nodes) { return done() }
each(nodes, (node, cb) => {
series([
(cb) => node.stop(cb)
], cb)
}, done)
}
return {
create,
connect,
tryConnectAll: tryConnectAllFn,
before,
after,
things: () => nodes,
connManagers: () => nodes.map((node) => node.connectionManager)
}
}

View File

@@ -0,0 +1,27 @@
'use strict'
const mapSeries = require('async/mapSeries')
const eachSeries = require('async/eachSeries')
module.exports = (nodes, callback) => {
mapSeries(
nodes,
(node, cb) => {
const connectedTo = []
eachSeries(
nodes.filter(n => node !== n),
(otherNode, cb) => {
const otherNodePeerInfo = otherNode.peerInfo
node.dial(otherNodePeerInfo, (err) => {
if (!err) {
connectedTo.push(otherNodePeerInfo.id.toB58String())
}
cb()
})
},
(err) => cb(err, connectedTo)
)
},
callback
)
}

View File

@@ -4,31 +4,124 @@
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const PeerBook = require('peer-book')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const MultiAddr = require('multiaddr')
const TestPeerInfos = require('./switch/test-data/ids.json').infos
const getPeerInfo = require('../src/get-peer-info')
const { getPeerInfo, getPeerInfoRemote } = require('../src/get-peer-info')
describe('getPeerInfo', () => {
it('should callback with error for invalid string multiaddr', (done) => {
getPeerInfo(null)('INVALID MULTIADDR', (err) => {
expect(err).to.exist()
expect(err.code).to.eql('ERR_INVALID_MULTIADDR')
done()
describe('Get Peer Info', () => {
describe('getPeerInfo', () => {
let peerBook
let peerInfoA
let multiaddrA
let peerIdA
before((done) => {
peerBook = new PeerBook()
PeerId.createFromJSON(TestPeerInfos[0].id, (err, id) => {
peerIdA = id
peerInfoA = new PeerInfo(peerIdA)
multiaddrA = MultiAddr('/ipfs/QmdWYwTywvXBeLKWthrVNjkq9SafEDn1PbAZdz4xZW7Jd9')
peerInfoA.multiaddrs.add(multiaddrA)
peerBook.put(peerInfoA)
done(err)
})
})
it('should be able get peer info from multiaddr', () => {
const _peerInfo = getPeerInfo(multiaddrA, peerBook)
expect(peerBook.has(_peerInfo)).to.equal(true)
expect(peerInfoA).to.deep.equal(_peerInfo)
})
it('should return a new PeerInfo with a multiAddr not in the PeerBook', () => {
const wrongMultiAddr = MultiAddr('/ipfs/QmckZzdVd72h9QUFuJJpQqhsZqGLwjhh81qSvZ9BhB2FQi')
const _peerInfo = getPeerInfo(wrongMultiAddr, peerBook)
expect(PeerInfo.isPeerInfo(_peerInfo)).to.equal(true)
})
it('should be able get peer info from peer id', () => {
const _peerInfo = getPeerInfo(multiaddrA, peerBook)
expect(peerBook.has(_peerInfo)).to.equal(true)
expect(peerInfoA).to.deep.equal(_peerInfo)
})
it('should add a peerInfo to the book', (done) => {
PeerId.createFromJSON(TestPeerInfos[1].id, (err, id) => {
const peerInfo = new PeerInfo(id)
expect(peerBook.has(peerInfo.id.toB58String())).to.eql(false)
expect(getPeerInfo(peerInfo, peerBook)).to.exist()
expect(peerBook.has(peerInfo.id.toB58String())).to.eql(true)
done(err)
})
})
it('should return the most up to date version of the peer', (done) => {
const ma1 = MultiAddr('/ip4/0.0.0.0/tcp/8080')
const ma2 = MultiAddr('/ip6/::/tcp/8080')
PeerId.createFromJSON(TestPeerInfos[1].id, (err, id) => {
const peerInfo = new PeerInfo(id)
peerInfo.multiaddrs.add(ma1)
expect(getPeerInfo(peerInfo, peerBook)).to.exist()
const peerInfo2 = new PeerInfo(id)
peerInfo2.multiaddrs.add(ma2)
const returnedPeerInfo = getPeerInfo(peerInfo2, peerBook)
expect(returnedPeerInfo.multiaddrs.toArray()).to.contain.members([
ma1, ma2
])
done(err)
})
})
it('an invalid peer type should throw an error', () => {
let error
try {
getPeerInfo('/ip4/127.0.0.1/tcp/1234', peerBook)
} catch (err) {
error = err
}
expect(error.code).to.eql('ERR_INVALID_MULTIADDR')
})
})
it('should callback with error for invalid non-peer multiaddr', (done) => {
getPeerInfo(null)('/ip4/8.8.8.8/tcp/1080', (err) => {
expect(err).to.exist()
expect(err.code).to.equal('ERR_INVALID_MULTIADDR')
done()
})
})
describe('getPeerInfoRemote', () => {
it('should callback with error for invalid string multiaddr', async () => {
let error
try {
await getPeerInfoRemote('INVALID MULTIADDR')
} catch (err) {
error = err
}
it('should callback with error for invalid non-peer multiaddr', (done) => {
getPeerInfo(null)(undefined, (err) => {
expect(err).to.exist()
expect(err.code).to.eql('ERR_INVALID_PEER_TYPE')
done()
expect(error.code).to.eql('ERR_INVALID_PEER_TYPE')
})
it('should callback with error for invalid non-peer multiaddr', async () => {
let error
try {
await getPeerInfoRemote('/ip4/8.8.8.8/tcp/1080')
} catch (err) {
error = err
}
expect(error.code).to.eql('ERR_INVALID_PEER_TYPE')
})
it('should callback with error for invalid non-peer multiaddr', async () => {
let error
try {
await getPeerInfoRemote(undefined)
} catch (err) {
error = err
}
expect(error.code).to.eql('ERR_INVALID_PEER_TYPE')
})
})
})

View File

@@ -0,0 +1,15 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const identify = require('libp2p-identify')
describe('basic', () => {
it('multicodec', () => {
expect(identify.multicodec).to.eql('/ipfs/id/1.0.0')
})
})

View File

@@ -0,0 +1,192 @@
/* eslint-env mocha */
'use strict'
const pull = require('pull-stream/pull')
const values = require('pull-stream/sources/values')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const pair = require('pull-pair/duplex')
const PeerInfo = require('peer-info')
const lp = require('pull-length-prefixed')
const multiaddr = require('multiaddr')
const msg = require('libp2p-identify').message
const identify = require('libp2p-identify')
describe('identify.dialer', () => {
let original
before(function (done) {
this.timeout(20 * 1000)
PeerInfo.create((err, info) => {
if (err) {
return done(err)
}
original = info
done()
})
})
afterEach(() => {
original.multiaddrs.clear()
original.protocols.clear()
})
it('works', (done) => {
const p = pair()
original.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
original.protocols.add('/echo/1.0.0')
original.protocols.add('/ping/1.0.0')
const input = msg.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: original.id.pubKey.bytes,
listenAddrs: [multiaddr('/ip4/127.0.0.1/tcp/5002').buffer],
observedAddr: multiaddr('/ip4/127.0.0.1/tcp/5001').buffer,
protocols: Array.from(original.protocols)
})
pull(
values([input]),
lp.encode(),
p[0]
)
identify.dialer(p[1], (err, info, observedAddrs) => {
expect(err).to.not.exist()
expect(info.id.pubKey.bytes)
.to.eql(original.id.pubKey.bytes)
expect(info.multiaddrs.has(original.multiaddrs.toArray()[0]))
.to.eql(true)
expect(multiaddr('/ip4/127.0.0.1/tcp/5001').equals(observedAddrs[0]))
.to.eql(true)
expect(info.protocols).to.eql(original.protocols)
done()
})
})
it('should handle missing protocols', (done) => {
const p = pair()
original.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
const input = msg.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: original.id.pubKey.bytes,
listenAddrs: [multiaddr('/ip4/127.0.0.1/tcp/5002').buffer],
observedAddr: multiaddr('/ip4/127.0.0.1/tcp/5001').buffer,
protocols: Array.from(original.protocols)
})
pull(
values([input]),
lp.encode(),
p[0]
)
identify.dialer(p[1], (err, info, observedAddrs) => {
expect(err).to.not.exist()
expect(info.id.pubKey.bytes)
.to.eql(original.id.pubKey.bytes)
expect(info.multiaddrs.has(original.multiaddrs.toArray()[0]))
.to.eql(true)
expect(multiaddr('/ip4/127.0.0.1/tcp/5001').equals(observedAddrs[0]))
.to.eql(true)
expect(Array.from(info.protocols)).to.eql([])
done()
})
})
it('does not crash with invalid listen addresses', (done) => {
const p = pair()
original.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
const input = msg.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: original.id.pubKey.bytes,
listenAddrs: [Buffer.from('ffac010203')],
observedAddr: Buffer.from('ffac010203')
})
pull(
values([input]),
lp.encode(),
p[0]
)
identify.dialer(p[1], (err, info, observedAddrs) => {
expect(err).to.exist()
done()
})
})
it('does not crash with invalid observed address', (done) => {
const p = pair()
original.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
const input = msg.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: original.id.pubKey.bytes,
listenAddrs: [multiaddr('/ip4/127.0.0.1/tcp/5002').buffer],
observedAddr: Buffer.from('ffac010203')
})
pull(
values([input]),
lp.encode(),
p[0]
)
identify.dialer(p[1], (err, info, observedAddrs) => {
expect(err).to.exist()
done()
})
})
it('should return an error with mismatched peerInfo data', function (done) {
this.timeout(10e3)
const p = pair()
original.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
const input = msg.encode({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: original.id.pubKey.bytes,
listenAddrs: [multiaddr('/ip4/127.0.0.1/tcp/5002').buffer],
observedAddr: multiaddr('/ip4/127.0.0.1/tcp/5001').buffer
})
PeerInfo.create((err, info) => {
if (err) {
return done(err)
}
pull(
values([input]),
lp.encode(),
p[0]
)
identify.dialer(p[1], info, (err, peerInfo) => {
expect(err).to.exist()
expect(peerInfo).to.not.exist()
done()
})
})
})
})

View File

@@ -0,0 +1,70 @@
/* eslint-env mocha */
'use strict'
const pull = require('pull-stream/pull')
const collect = require('pull-stream/sinks/collect')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const pair = require('pull-pair/duplex')
const PeerInfo = require('peer-info')
const lp = require('pull-length-prefixed')
const multiaddr = require('multiaddr')
const msg = require('libp2p-identify').message
const identify = require('libp2p-identify')
describe('identify.listener', () => {
let info
beforeEach(function (done) {
this.timeout(20 * 1000)
PeerInfo.create((err, _info) => {
if (err) {
return done(err)
}
_info.protocols.add('/echo/1.0.0')
_info.protocols.add('/chat/1.0.0')
info = _info
done()
})
})
it('works', (done) => {
const p = pair()
info.multiaddrs.add(multiaddr('/ip4/127.0.0.1/tcp/5002'))
pull(
p[1],
lp.decode(),
collect((err, result) => {
expect(err).to.not.exist()
const input = msg.decode(result[0])
expect(
input
).to.be.eql({
protocolVersion: 'ipfs/0.1.0',
agentVersion: 'na',
publicKey: info.id.pubKey.bytes,
listenAddrs: [multiaddr('/ip4/127.0.0.1/tcp/5002').buffer],
observedAddr: multiaddr('/ip4/127.0.0.1/tcp/5001').buffer,
protocols: ['/echo/1.0.0', '/chat/1.0.0']
})
done()
})
)
const conn = p[0]
conn.getObservedAddrs = (cb) => {
cb(null, [multiaddr('/ip4/127.0.0.1/tcp/5001')])
}
identify.listener(conn, info)
})
})

View File

@@ -14,4 +14,5 @@ require('./multiaddr-trim.node')
require('./stats')
require('./dht.node')
require('./ping/node')
require('./switch/node')

3
test/ping/node.js Normal file
View File

@@ -0,0 +1,3 @@
'use strict'
require('./test-ping.js')

118
test/ping/test-ping.js Normal file
View File

@@ -0,0 +1,118 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book')
const Swarm = require('libp2p-switch')
const TCP = require('libp2p-tcp')
const series = require('async/series')
const parallel = require('async/parallel')
const Ping = require('libp2p-ping')
describe('libp2p ping', () => {
let swarmA
let swarmB
let peerA
let peerB
before(function (done) {
this.timeout(20 * 1000)
series([
(cb) => PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
peerA = peerInfo
peerA.multiaddrs.add('/ip4/127.0.0.1/tcp/0')
cb()
}),
(cb) => PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
peerB = peerInfo
peerB.multiaddrs.add('/ip4/127.0.0.1/tcp/0')
cb()
}),
(cb) => {
swarmA = new Swarm(peerA, new PeerBook())
swarmB = new Swarm(peerB, new PeerBook())
swarmA.transport.add('tcp', new TCP())
swarmB.transport.add('tcp', new TCP())
cb()
},
(cb) => swarmA.start(cb),
(cb) => swarmB.start(cb),
(cb) => {
Ping.mount(swarmA)
Ping.mount(swarmB)
cb()
}
], done)
})
after((done) => {
parallel([
(cb) => swarmA.stop(cb),
(cb) => swarmB.stop(cb)
], done)
})
it('ping once from peerA to peerB', (done) => {
const p = new Ping(swarmA, peerB)
p.on('error', (err) => {
expect(err).to.not.exist()
})
p.on('ping', (time) => {
expect(time).to.be.a('Number')
p.stop()
done()
})
p.start()
})
it('ping 5 times from peerB to peerA', (done) => {
const p = new Ping(swarmB, peerA)
p.on('error', (err) => {
expect(err).to.not.exist()
})
let counter = 0
p.on('ping', (time) => {
expect(time).to.be.a('Number')
if (++counter === 5) {
p.stop()
done()
}
})
p.start()
})
it('cannot ping itself', (done) => {
const p = new Ping(swarmA, peerA)
p.on('error', (err) => {
expect(err).to.exist()
done()
})
p.on('ping', () => {
expect.fail('should not be called')
})
p.start()
})
it('unmount PING protocol', () => {
Ping.unmount(swarmA)
Ping.unmount(swarmB)
})
})

View File

@@ -0,0 +1,5 @@
{
"id": "QmeS1ou3mrjCFGoFtRx3MwrGDzqKD6xbuYJU1CKtMrtFFu",
"privKey": "CAASqAkwggSkAgEAAoIBAQChwzYwCNIyUkzEK3sILqq9ChAKZ9eU+ribY+B/xwAwDKPfvuqHq0hjauJBMcjiQyKAWz9xEBR3WupOM7h9M8oU+/e0xJUTt/CDOrtJ0PCgUXeBLkqsApbBoXW3yomHEDHxYttKzrtoTimiP1bhrxurcpVNC4CUYD+q8gw3sRZlsrqpeYYAfU04kS0BM75W/sUT90znnHvOxFXrEdMMdenEFhZOsDyEK9ENzwhkKgOGb18MBY4kN5DoW4bVd4ItfZnNwdkQtpP/X99tMWJxO4yqpngbywZGnkfirLeuRwt/xRGFVbLOigjBpTVpcbBqe1t2Flhuf/bfWYX4FbyElA5FAgMBAAECggEAJnDTcbrG6LpyD7QdeqZMYLwBb9eZfYfPUu37LaJGwyRd1Q/zf+YOP8HonoGMMWiuzD3i56Vgl7R9NbRIxUgHX9E43jZRDuyJNUZBt5r1c8OoWIR9rj63QLBz3wc8g2Iv3CMX5cEW/ASHFE1lAiCwvJ9wJ2zyU1BEEQWQLbPhlKzw7SLhr4fee45/7pnrKZMllt5vwC9pM6lrpIkICO5gUu0OWu5wfzzlTvfmCgfTb11VqKESEPbDBMUtpJibRqegE4xvipLklJ8VV8jz7NFs9bhgCpNM74Ngt5vGHcddeqtj//86UsClEw5YgWAdRe29ZjMApWvKIkginLjZEO8eiQKBgQDoDWii0rmlgBl1/8fENUSWxYvknGmWO7eWjVqMjDvA+waWUVDpTE+eHT1QAaPofM+nFz5PG+SpB55o4rXdxDesq+DqnaRAI9WtSHdgRtjgETyqoBAiahQ0zGWmSEYHGDB+xGctTMr8GxdhZxqZjjfyptp6oXXqZkmxgcogrx+WTwKBgQCydNDmCDpeH0kSvhAPxaNx5c9WkFEFSA0OCZOx57Y+Mt0MVamRILFrUrcMz095w8BQZkjlHjSHfsRgKa/b2eOd+3BhoMLZVtxRqBdpdqq1KTAcRRG4yA2KA39rttpVzaTV5SPfdDf3tsVlBtV784W63gVpN9gNfajyyrpeffiBKwKBgDnDrLprbl8uZigjhdznza0ie9JqxTXqo6bMhS/bcLx3QIqGr3eD0YXwjWSvI9gpyZ80gAQ9U0xoYxyE4vTTdXB8UL7Wgx6cTQKXuW+z8yTD5bArrBiFA4apItyjvRrjAJ9t0KlMJnNfYxCSE+MJrg+vTU+dhbbVw552SpScQ2atAoGBAKMu3rb6XyUiRpe05MsHVuYX1vi5Dt1dfVKQv1W3JJbLvAZDbsMeuh4BjRFRoMMflQPwBEg+zpn3+WpVtFG9dL5J5gHgF0zWeLDSnFX8BS2TdELlhccKaBcEC8hbdFtxqIFO/vaeN2902hv/m8e0b1zpGNmWDyKG/a7GYpV1a3/xAoGBAJtgGANDVk6qqcWGEVk56FH1ZksvgF3SPXWaXpzbZ5KLCcV5ooRyhowylKUZBBPowMeZ46tem2xwJbraB5kDg6WiSjBsXcbN95ivb8AuoRa6gDqAszjokQUSdpY7FTgMaL046AuihrKsQSly1jrQqbQu8JBgmnnBzus3s77inL/j",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChwzYwCNIyUkzEK3sILqq9ChAKZ9eU+ribY+B/xwAwDKPfvuqHq0hjauJBMcjiQyKAWz9xEBR3WupOM7h9M8oU+/e0xJUTt/CDOrtJ0PCgUXeBLkqsApbBoXW3yomHEDHxYttKzrtoTimiP1bhrxurcpVNC4CUYD+q8gw3sRZlsrqpeYYAfU04kS0BM75W/sUT90znnHvOxFXrEdMMdenEFhZOsDyEK9ENzwhkKgOGb18MBY4kN5DoW4bVd4ItfZnNwdkQtpP/X99tMWJxO4yqpngbywZGnkfirLeuRwt/xRGFVbLOigjBpTVpcbBqe1t2Flhuf/bfWYX4FbyElA5FAgMBAAE="
}

View File

@@ -0,0 +1,5 @@
{
"id": "QmYWHGZ9y1Bzx59bBzn85JsJxwmpBy5bpXDWDfwMfsHsxz",
"privKey": "CAASqQkwggSlAgEAAoIBAQDLVaPqWFA8WgK6ixuPvhTHeQfBblmEFLEmraLlIDSWbMUPva6aJ1V/hi2I5QLXNeeiig5sco+nF+RKhGnzQ9NpgHRVZ7Ze+LWq3Q4YxONdzFeNUjTvJrDSKgkubA5EKC/LI6pU33WZbjyKkomGo+Gzuqvlj4Rx1dLVXRIOjxUYcIQw3vpLQgwPpiz52eWCeoCpzn06DcsF6aNPjhlp9uJRZCRxZ4yeiwh/A0xxiQtnB4fdZuUPmia1r62+oaxrDl4hUwR7kzHYl0YGfXxAW9GT17KGtjES2yO4kAUgquelNh0hgBKZRvny9imwsObG7ntw5ZG7H62sP7UySIUJqoNRAgMBAAECggEBAKLVU25BCQg7wQGokwra2wMfPoG+IDuw4mkqFlBNKS/prSo86c2TgFmel2qQk2TLS1OUIZbha38RmAXA4qQohe5wKzmV06tcmwdY/YgCbF5aXSbUVYXLQ0Ea3r1pVUdps1SHnElZpnCXoi4Kyc2kAgSPkkdFVnhfFvc9EE/Ob8NgMkdFhlosE5WVNqm4BKQ+mqONddSz4JDbDOApPs/rRpgYm7pJKc3vkrYwniPjyQGYb5EoSbSWuu31RzIcn3Bhte3wKtfMMlpn8MMpPiYo2WJ2eVG6hlUOxhHgS93Y6czCfAgsDtD3C2JpteewuBjg8N0d6WRArKxny83J34q0qy0CgYEA6YSo5UDEq1TF8sbtSVYg6MKSX92NO5MQI/8fTjU4tEwxn/yxpGsnqUu0WGYIc2qVaZuxtcnk2CQxEilxQTbWSIxKuTt7qofEcpSjLLQ4f4chk4DpPsba+S8zSUdWdjthPHZT9IYzobylGBLfbPxyXXiYn1VuqAJfFy8iV9XqmdcCgYEA3ukROQQZCJcgsNTc5uFAKUeQvzv1iae3fGawgJmIJW3Bl8+4dSm1diqG3ZXP1WU31no2aX50PqOZjoIpbl1ggT76cnBDuu3pItR3dNJFQyMEpQOWOjO+NBWF7sRswCvlqbyjofWkzsdd0BioL7vWMjPftiusyyAFA55HRoeStxcCgYEA0tP7rKdSKKFr6inhl+GT6rGod7bOSSgYXXd7qx9v55AXCauaMqiv8TAxTdIo9RMYfHWd91OlMeNTDmOuJcO9qVhIKn5iw266VPyPac/4ZmL5VHQBobTlhC4yLomirTIlMvJeEBmNygtIPrjjUUGGe49itA/szPD/Ky5Z4lV27pcCgYAWU3mqIELxnVFk5K0LYtwuRkC1Jqg9FVNHXnGnL7l3JjsRnXh4I6lNII1JfEvIr86b6LmybzvtWi1zHI5Rw4B68XfcJmpiOpnzJxyf0r+lLci1Tlqpka0nQlCbzYim5r6l9YLeIeBT5Zv7z7xoq4OUm6V4dX9lCNv3tM6mvcVwGQKBgQC9hhjD64/VKXL8wYKZyTAOVO5xYCcqylrpI39qdzl+sS8oqmLUbXnKsGY4If9U61XdULld41BJCRlv6CsKreynm6ZN41j9YRuWWLu8STJcniV9Ef9uVl1M1zo8kfnCHMCym9LkTfJY+Ow/kYhqPukJJL6ve1CVmIuA4rnZlshjbg==",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLVaPqWFA8WgK6ixuPvhTHeQfBblmEFLEmraLlIDSWbMUPva6aJ1V/hi2I5QLXNeeiig5sco+nF+RKhGnzQ9NpgHRVZ7Ze+LWq3Q4YxONdzFeNUjTvJrDSKgkubA5EKC/LI6pU33WZbjyKkomGo+Gzuqvlj4Rx1dLVXRIOjxUYcIQw3vpLQgwPpiz52eWCeoCpzn06DcsF6aNPjhlp9uJRZCRxZ4yeiwh/A0xxiQtnB4fdZuUPmia1r62+oaxrDl4hUwR7kzHYl0YGfXxAW9GT17KGtjES2yO4kAUgquelNh0hgBKZRvny9imwsObG7ntw5ZG7H62sP7UySIUJqoNRAgMBAAE="
}

105
test/pnet/pnet.spec.js Normal file
View File

@@ -0,0 +1,105 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
chai.use(dirtyChai)
const expect = chai.expect
const parallel = require('async/parallel')
const PeerId = require('peer-id')
const Connection = require('interface-connection').Connection
const pair = require('pull-pair/duplex')
const pull = require('pull-stream')
const Protector = require('libp2p-pnet')
const Errors = Protector.errors
const generate = Protector.generate
const swarmKeyBuffer = Buffer.alloc(95)
const wrongSwarmKeyBuffer = Buffer.alloc(95)
// Write new psk files to the buffers
generate(swarmKeyBuffer)
generate(wrongSwarmKeyBuffer)
describe('private network', () => {
before((done) => {
parallel([
(cb) => PeerId.createFromJSON(require('./fixtures/peer-a'), cb),
(cb) => PeerId.createFromJSON(require('./fixtures/peer-b'), cb)
], (err) => {
expect(err).to.not.exist()
done()
})
})
it('should accept a valid psk buffer', () => {
const protector = new Protector(swarmKeyBuffer)
expect(protector.tag).to.equal('/key/swarm/psk/1.0.0/')
expect(protector.psk.byteLength).to.equal(32)
})
it('should protect a simple connection', (done) => {
const p = pair()
const protector = new Protector(swarmKeyBuffer)
const aToB = protector.protect(new Connection(p[0]), (err) => {
expect(err).to.not.exist()
})
const bToA = protector.protect(new Connection(p[1]), (err) => {
expect(err).to.not.exist()
})
pull(
pull.values([Buffer.from('hello world'), Buffer.from('doo dah')]),
aToB
)
pull(
bToA,
pull.collect((err, chunks) => {
expect(err).to.not.exist()
expect(chunks).to.eql([Buffer.from('hello world'), Buffer.from('doo dah')])
done()
})
)
})
it('should not connect to a peer with a different key', (done) => {
const p = pair()
const protector = new Protector(swarmKeyBuffer)
const protectorB = new Protector(wrongSwarmKeyBuffer)
const aToB = protector.protect(new Connection(p[0]), () => { })
const bToA = protectorB.protect(new Connection(p[1]), () => { })
pull(
pull.values([Buffer.from('hello world'), Buffer.from('doo dah')]),
aToB
)
pull(
bToA,
pull.collect((values) => {
expect(values).to.equal(null)
done()
})
)
})
describe('invalid psks', () => {
it('should not accept a bad psk', () => {
expect(() => {
return new Protector(Buffer.from('not-a-key'))
}).to.throw(Errors.INVALID_PSK)
})
it('should not accept a psk of incorrect length', () => {
expect(() => {
return new Protector(Buffer.from('/key/swarm/psk/1.0.0/\n/base16/\ndffb7e'))
}).to.throw(Errors.INVALID_PSK)
})
})
})

View File

@@ -1,366 +0,0 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const sinon = require('sinon')
const once = require('once')
const parallel = require('async/parallel')
const series = require('async/series')
const TCP = require('libp2p-tcp')
const WS = require('libp2p-websockets')
const multiplex = require('pull-mplex')
const PeerBook = require('peer-book')
const getPorts = require('portfinder').getPorts
const utils = require('./utils')
const createInfos = utils.createInfos
const Swarm = require('libp2p-switch')
const switchOptions = {
denyTTL: 0 // nullifies denylisting
}
describe(`circuit`, function () {
describe('basic', () => {
let swarmA // TCP and WS
let swarmB // WS
let swarmC // no transports
let dialSpyA
before((done) => createInfos(3, (err, infos) => {
expect(err).to.not.exist()
const peerA = infos[0]
const peerB = infos[1]
const peerC = infos[2]
peerA.multiaddrs.add('/ip4/0.0.0.0/tcp/9001')
peerB.multiaddrs.add('/ip4/127.0.0.1/tcp/9002/ws')
swarmA = new Swarm(peerA, new PeerBook(), switchOptions)
swarmB = new Swarm(peerB, new PeerBook())
swarmC = new Swarm(peerC, new PeerBook())
swarmA.transport.add('tcp', new TCP())
swarmA.transport.add('ws', new WS())
swarmB.transport.add('ws', new WS())
dialSpyA = sinon.spy(swarmA.transport, 'dial')
done()
}))
after((done) => {
parallel([
(cb) => swarmA.stop(cb),
(cb) => swarmB.stop(cb)
], done)
})
it('circuit not enabled and all transports failed', (done) => {
swarmA.dial(swarmC._peerInfo, (err, conn) => {
expect(err).to.exist()
expect(err).to.match(/Circuit not enabled and all transports failed to dial peer/)
expect(conn).to.not.exist()
done()
})
})
it('.enableCircuitRelay', () => {
swarmA.connection.enableCircuitRelay({ enabled: true })
expect(Object.keys(swarmA.transports).length).to.equal(3)
swarmB.connection.enableCircuitRelay({ enabled: true })
expect(Object.keys(swarmB.transports).length).to.equal(2)
})
it('listed on the transports map', () => {
expect(swarmA.transports.Circuit).to.exist()
expect(swarmB.transports.Circuit).to.exist()
})
it('add /p2p-circuit addrs on start', (done) => {
parallel([
(cb) => swarmA.start(cb),
(cb) => swarmB.start(cb)
], (err) => {
expect(err).to.not.exist()
expect(swarmA._peerInfo.multiaddrs.toArray().filter((a) => a.toString()
.includes(`/p2p-circuit`)).length).to.be.at.least(3)
// ensure swarmA has had 0.0.0.0 replaced in the addresses
expect(swarmA._peerInfo.multiaddrs.toArray().filter((a) => a.toString()
.includes(`/0.0.0.0`)).length).to.equal(0)
expect(swarmB._peerInfo.multiaddrs.toArray().filter((a) => a.toString()
.includes(`/p2p-circuit`)).length).to.be.at.least(2)
done()
})
})
it('dial circuit only once', (done) => {
swarmA._peerInfo.multiaddrs.clear()
swarmA._peerInfo.multiaddrs
.add(`/dns4/wrtc-star.discovery.libp2p.io/tcp/443/wss/p2p-webrtc-star`)
swarmA.dial(swarmC._peerInfo, (err, conn) => {
expect(err).to.exist()
expect(err).to.match(/No available transports to dial peer/)
expect(conn).to.not.exist()
expect(dialSpyA.callCount).to.be.eql(1)
done()
})
})
it('dial circuit last', (done) => {
const peerC = swarmC._peerInfo
peerC.multiaddrs.clear()
peerC.multiaddrs.add(`/p2p-circuit/ipfs/ABCD`)
peerC.multiaddrs.add(`/ip4/127.0.0.1/tcp/9998/ipfs/ABCD`)
peerC.multiaddrs.add(`/ip4/127.0.0.1/tcp/9999/ws/ipfs/ABCD`)
swarmA.dial(peerC, (err, conn) => {
expect(err).to.exist()
expect(conn).to.not.exist()
expect(dialSpyA.lastCall.args[0]).to.be.eql('Circuit')
done()
})
})
it('should not try circuit if no transports enabled', (done) => {
swarmC.dial(swarmA._peerInfo, (err, conn) => {
expect(err).to.exist()
expect(conn).to.not.exist()
expect(err).to.match(/No transports registered, dial not possible/)
done()
})
})
it('should not dial circuit if other transport succeed', (done) => {
swarmA.dial(swarmB._peerInfo, (err) => {
expect(err).not.to.exist()
expect(dialSpyA.lastCall.args[0]).to.not.be.eql('Circuit')
done()
})
})
})
describe('in a basic network', () => {
// Create 5 nodes
// Make node 1 act as a Bootstrap node and relay (speak tcp and ws)
// Make nodes 2 & 3 speak tcp only
// Make nodes 4 & 5 speak WS only
// Have all nodes dial node 1
// Each node should get the peers of node 1
// Attempt to dial to each peer
let bootstrapSwitch
let tcpSwitch1
let tcpSwitch2
let wsSwitch1
let wsSwitch2
let bootstrapPeer
let tcpPeer1
let tcpPeer2
let wsPeer1
let wsPeer2
before((done) => createInfos(5, (err, infos) => {
expect(err).to.not.exist()
getPorts(6, (err, ports) => {
expect(err).to.not.exist()
bootstrapPeer = infos[0]
tcpPeer1 = infos[1]
tcpPeer2 = infos[2]
wsPeer1 = infos[3]
wsPeer2 = infos[4]
// Setup the addresses of our nodes
bootstrapPeer.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}`)
bootstrapPeer.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}/ws`)
tcpPeer1.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}`)
tcpPeer2.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}`)
wsPeer1.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}/ws`)
wsPeer2.multiaddrs.add(`/ip4/0.0.0.0/tcp/${ports.shift()}/ws`)
// Setup the bootstrap node with the minimum needed for being a relay
bootstrapSwitch = new Swarm(bootstrapPeer, new PeerBook())
bootstrapSwitch.connection.addStreamMuxer(multiplex)
bootstrapSwitch.connection.reuse()
bootstrapSwitch.connection.enableCircuitRelay({
enabled: true,
// The relay needs to allow hopping
hop: {
enabled: true
}
})
// Setup the tcp1 node with the minimum needed for dialing via a relay
tcpSwitch1 = new Swarm(tcpPeer1, new PeerBook())
tcpSwitch1.connection.addStreamMuxer(multiplex)
tcpSwitch1.connection.reuse()
tcpSwitch1.connection.enableCircuitRelay({
enabled: true
})
// Setup tcp2 node to not be able to dial/listen over relay
tcpSwitch2 = new Swarm(tcpPeer2, new PeerBook())
tcpSwitch2.connection.reuse()
tcpSwitch2.connection.addStreamMuxer(multiplex)
// Setup the ws1 node with the minimum needed for dialing via a relay
wsSwitch1 = new Swarm(wsPeer1, new PeerBook())
wsSwitch1.connection.addStreamMuxer(multiplex)
wsSwitch1.connection.reuse()
wsSwitch1.connection.enableCircuitRelay({
enabled: true
})
// Setup the ws2 node with the minimum needed for dialing via a relay
wsSwitch2 = new Swarm(wsPeer2, new PeerBook())
wsSwitch2.connection.addStreamMuxer(multiplex)
wsSwitch2.connection.reuse()
wsSwitch2.connection.enableCircuitRelay({
enabled: true
})
bootstrapSwitch.transport.add('tcp', new TCP())
bootstrapSwitch.transport.add('ws', new WS())
tcpSwitch1.transport.add('tcp', new TCP())
tcpSwitch2.transport.add('tcp', new TCP())
wsSwitch1.transport.add('ws', new WS())
wsSwitch2.transport.add('ws', new WS())
series([
// start the nodes
(cb) => {
parallel([
(cb) => bootstrapSwitch.start(cb),
(cb) => tcpSwitch1.start(cb),
(cb) => tcpSwitch2.start(cb),
(cb) => wsSwitch1.start(cb),
(cb) => wsSwitch2.start(cb)
], cb)
},
// dial to the bootstrap node
(cb) => {
parallel([
(cb) => tcpSwitch1.dial(bootstrapPeer, cb),
(cb) => tcpSwitch2.dial(bootstrapPeer, cb),
(cb) => wsSwitch1.dial(bootstrapPeer, cb),
(cb) => wsSwitch2.dial(bootstrapPeer, cb)
], cb)
}
], (err) => {
if (err) return done(err)
if (bootstrapSwitch._peerBook.getAllArray().length === 4) {
return done()
}
done = once(done)
// Wait for everyone to connect, before we try relaying
bootstrapSwitch.on('peer-mux-established', () => {
if (bootstrapSwitch._peerBook.getAllArray().length === 4) {
done()
}
})
})
})
}))
before('wait so hop status can be negotiated', function (done) {
setTimeout(done, 1000)
})
after(function (done) {
parallel([
(cb) => bootstrapSwitch.stop(cb),
(cb) => tcpSwitch1.stop(cb),
(cb) => tcpSwitch2.stop(cb),
(cb) => wsSwitch1.stop(cb),
(cb) => wsSwitch2.stop(cb)
], done)
})
it('should be able to dial tcp -> tcp', (done) => {
tcpSwitch2.on('peer-mux-established', (peerInfo) => {
if (peerInfo.id.toB58String() === tcpPeer1.id.toB58String()) {
tcpSwitch2.removeAllListeners('peer-mux-established')
done()
}
})
tcpSwitch1.dial(tcpPeer2, (err, connection) => {
expect(err).to.not.exist()
// We're not dialing a protocol, so we won't get a connection back
expect(connection).to.be.undefined()
})
})
it('should be able to dial tcp -> ws over relay', (done) => {
wsSwitch1.on('peer-mux-established', (peerInfo) => {
if (peerInfo.id.toB58String() === tcpPeer1.id.toB58String()) {
wsSwitch1.removeAllListeners('peer-mux-established')
done()
}
})
tcpSwitch1.dial(wsPeer1, (err, connection) => {
expect(err).to.not.exist()
// We're not dialing a protocol, so we won't get a connection back
expect(connection).to.be.undefined()
})
})
it('should be able to dial ws -> ws', (done) => {
wsSwitch2.on('peer-mux-established', (peerInfo) => {
if (peerInfo.id.toB58String() === wsPeer1.id.toB58String()) {
wsSwitch2.removeAllListeners('peer-mux-established')
done()
}
})
wsSwitch1.dial(wsPeer2, (err, connection) => {
expect(err).to.not.exist()
// We're not dialing a protocol, so we won't get a connection back
expect(connection).to.be.undefined()
})
})
it('should be able to dial ws -> tcp over relay', (done) => {
tcpSwitch1.on('peer-mux-established', (peerInfo) => {
if (peerInfo.id.toB58String() === wsPeer2.id.toB58String()) {
tcpSwitch1.removeAllListeners('peer-mux-established')
expect(Object.keys(tcpSwitch1._peerBook.getAll())).to.include(wsPeer2.id.toB58String())
done()
}
})
wsSwitch2.dial(tcpPeer1, (err, connection) => {
expect(err).to.not.exist()
// We're not dialing a protocol, so we won't get a connection back
expect(connection).to.be.undefined()
})
})
it('shouldnt be able to dial to a non relay node', (done) => {
// tcpPeer2 doesnt have relay enabled
wsSwitch1.dial(tcpPeer2, (err, connection) => {
expect(err).to.exist()
expect(connection).to.not.exist()
done()
})
})
it('shouldnt be able to dial from a non relay node', (done) => {
// tcpSwitch2 doesnt have relay enabled
tcpSwitch2.dial(wsPeer1, (err, connection) => {
expect(err).to.exist()
expect(connection).to.not.exist()
done()
})
})
})
})

View File

@@ -13,7 +13,6 @@ const secio = require('libp2p-secio')
const pull = require('pull-stream')
const multiplex = require('pull-mplex')
const spdy = require('libp2p-spdy')
const Connection = require('interface-connection').Connection
const Protector = require('libp2p-pnet')
const generatePSK = Protector.generate
@@ -104,7 +103,7 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
done()
})
@@ -118,7 +117,7 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
expect(() => connection.close(new Error('shutting down'))).to.not.throw()
done()
})
@@ -171,11 +170,11 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
done()
})
@@ -192,7 +191,7 @@ describe('ConnectionFSM', () => {
.callsArgWith(3, new Error('fail encrypt'))
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('close', () => {
@@ -213,11 +212,11 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.upgrade()
})
connection.once('muxed', (conn) => {
@@ -235,11 +234,11 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.upgrade()
})
connection.once('error:upgrade_failed', (err) => {
@@ -261,11 +260,11 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.upgrade()
})
connection.once('muxed', (conn) => {
@@ -273,7 +272,7 @@ describe('ConnectionFSM', () => {
connection.shake('/muxed-conn-test/1.0.0', (err, protocolConn) => {
expect(err).to.not.exist()
expect(protocolConn).to.be.an.instanceof(Connection)
expect(protocolConn).to.exist()
done()
})
})
@@ -292,11 +291,11 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.upgrade()
})
connection.once('muxed', (conn) => {
@@ -334,22 +333,22 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.upgrade()
})
connection.once('muxed', () => {
throw new Error('connection shouldnt be muxed')
})
connection.once('unmuxed', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.shake('/unmuxed-conn-test/1.0.0', (err, protocolConn) => {
expect(err).to.not.exist()
expect(protocolConn).to.be.an.instanceof(Connection)
expect(protocolConn).to.exist()
done()
})
})
@@ -386,12 +385,12 @@ describe('ConnectionFSM', () => {
})
connection.once('private', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
done()
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.protect()
})
@@ -420,7 +419,7 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection).mark()
expect(conn).to.exist().mark()
connection.protect()
})
@@ -434,15 +433,15 @@ describe('ConnectionFSM', () => {
})
connection.once('connected', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.protect()
})
connection.once('private', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
connection.encrypt()
})
connection.once('encrypted', (conn) => {
expect(conn).to.be.an.instanceof(Connection)
expect(conn).to.exist()
done()
})

View File

@@ -1,102 +0,0 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const PeerBook = require('peer-book')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const MultiAddr = require('multiaddr')
const TestPeerInfos = require('./test-data/ids.json').infos
const getPeerInfo = require('libp2p-switch/get-peer-info')
describe('Get peer info', () => {
let peerBook
let peerInfoA
let multiaddrA
let peerIdA
before((done) => {
peerBook = new PeerBook()
PeerId.createFromJSON(TestPeerInfos[0].id, (err, id) => {
peerIdA = id
peerInfoA = new PeerInfo(peerIdA)
multiaddrA = MultiAddr('/ipfs/QmdWYwTywvXBeLKWthrVNjkq9SafEDn1PbAZdz4xZW7Jd9')
peerInfoA.multiaddrs.add(multiaddrA)
peerBook.put(peerInfoA)
done(err)
})
})
it('should be able get peer info from multiaddr', () => {
const _peerInfo = getPeerInfo(multiaddrA, peerBook)
expect(peerBook.has(_peerInfo)).to.equal(true)
expect(peerInfoA).to.deep.equal(_peerInfo)
})
it('should return a new PeerInfo with a multiAddr not in the PeerBook', () => {
const wrongMultiAddr = MultiAddr('/ipfs/QmckZzdVd72h9QUFuJJpQqhsZqGLwjhh81qSvZ9BhB2FQi')
const _peerInfo = getPeerInfo(wrongMultiAddr, peerBook)
expect(PeerInfo.isPeerInfo(_peerInfo)).to.equal(true)
expect(peerBook.has(_peerInfo)).to.equal(false)
})
it('should be able get peer info from peer id', () => {
const _peerInfo = getPeerInfo(multiaddrA, peerBook)
expect(peerBook.has(_peerInfo)).to.equal(true)
expect(peerInfoA).to.deep.equal(_peerInfo)
})
it('should not be able to get the peer info for a wrong peer id', (done) => {
PeerId.createFromJSON(TestPeerInfos[1].id, (err, id) => {
const func = () => {
getPeerInfo(id, peerBook)
}
expect(func).to.throw('Couldnt get PeerInfo')
done(err)
})
})
it('should add a peerInfo to the book', (done) => {
PeerId.createFromJSON(TestPeerInfos[1].id, (err, id) => {
const peerInfo = new PeerInfo(id)
expect(peerBook.has(peerInfo.id.toB58String())).to.eql(false)
expect(getPeerInfo(peerInfo, peerBook)).to.exist()
expect(peerBook.has(peerInfo.id.toB58String())).to.eql(true)
done(err)
})
})
it('should return the most up to date version of the peer', (done) => {
const ma1 = MultiAddr('/ip4/0.0.0.0/tcp/8080')
const ma2 = MultiAddr('/ip6/::/tcp/8080')
PeerId.createFromJSON(TestPeerInfos[1].id, (err, id) => {
const peerInfo = new PeerInfo(id)
peerInfo.multiaddrs.add(ma1)
expect(getPeerInfo(peerInfo, peerBook)).to.exist()
const peerInfo2 = new PeerInfo(id)
peerInfo2.multiaddrs.add(ma2)
const returnedPeerInfo = getPeerInfo(peerInfo2, peerBook)
expect(returnedPeerInfo.multiaddrs.toArray()).to.contain.members([
ma1, ma2
])
done(err)
})
})
it('an invalid peer type should throw an error', () => {
const func = () => {
getPeerInfo('/ip4/127.0.0.1/tcp/1234', peerBook)
}
expect(func).to.throw('peer type not recognized')
})
})

View File

@@ -7,7 +7,7 @@ chai.use(require('chai-checkmark'))
const expect = chai.expect
const multiaddr = require('multiaddr')
const pull = require('pull-stream')
const setImmediate = require('async/setImmediate')
const nextTick = require('async/nextTick')
const LimitDialer = require('libp2p-switch/limit-dialer')
const utils = require('./utils')
@@ -37,14 +37,14 @@ describe('LimitDialer', () => {
// mock transport
const t1 = {
dial (addr, cb) {
setTimeout(() => cb(error), 1)
nextTick(cb, error)
return {}
}
}
dialer.dialMany(peers[0].id, t1, peers[0].multiaddrs.toArray(), (err, conn) => {
expect(err).to.exist()
expect(err).to.eql([error, error, error])
expect(err).to.include.members([error, error, error])
expect(conn).to.not.exist()
done()
})
@@ -58,16 +58,16 @@ describe('LimitDialer', () => {
dial (addr, cb) {
const as = addr.toString()
if (as.match(/191/)) {
setImmediate(() => cb(new Error('fail')))
nextTick(cb, new Error('fail'))
return null
} else if (as.match(/192/)) {
setTimeout(cb, 2)
nextTick(cb)
return {
source: pull.values([1]),
sink: pull.drain()
}
} else if (as.match(/193/)) {
setTimeout(cb, 8)
nextTick(cb)
return {
source: pull.values([2]),
sink: pull.drain()

View File

@@ -8,7 +8,6 @@ require('./stream-muxers.node')
require('./secio.node')
require('./swarm-no-muxing.node')
require('./swarm-muxing.node')
require('./circuit-relay.node')
require('./identify.node')
require('./limit-dialer.node')
require('./stats.node')