mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-08-01 00:41:57 +00:00
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:
303
test/circuit/dialer.spec.js
Normal file
303
test/circuit/dialer.spec.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
25
test/circuit/fixtures/nodes.js
Normal file
25
test/circuit/fixtures/nodes.js
Normal 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='
|
||||
}
|
22
test/circuit/helpers/test-node.js
Normal file
22
test/circuit/helpers/test-node.js
Normal 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
|
78
test/circuit/helpers/utils.js
Normal file
78
test/circuit/helpers/utils.js
Normal 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
433
test/circuit/hop.spec.js
Normal 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))
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
292
test/circuit/listener.spec.js
Normal file
292
test/circuit/listener.spec.js
Normal 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`)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
50
test/circuit/proto.spec.js
Normal file
50
test/circuit/proto.spec.js
Normal 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
85
test/circuit/stop.spec.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
19
test/connection-manager/default.js
Normal file
19
test/connection-manager/default.js
Normal 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)
|
||||
})
|
||||
})
|
36
test/connection-manager/max-data.js
Normal file
36
test/connection-manager/max-data.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
59
test/connection-manager/max-event-loop-delay.js
Normal file
59
test/connection-manager/max-event-loop-delay.js
Normal 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')
|
||||
}
|
||||
}
|
37
test/connection-manager/max-peer-per-protocol.js
Normal file
37
test/connection-manager/max-peer-per-protocol.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
35
test/connection-manager/max-peers.js
Normal file
35
test/connection-manager/max-peers.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
36
test/connection-manager/max-received-data.js
Normal file
36
test/connection-manager/max-received-data.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
36
test/connection-manager/max-sent-data.js
Normal file
36
test/connection-manager/max-sent-data.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
10
test/connection-manager/node.js
Normal file
10
test/connection-manager/node.js
Normal 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')
|
44
test/connection-manager/set-peer-value.js
Normal file
44
test/connection-manager/set-peer-value.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
17
test/connection-manager/utils/connect-all.js
Normal file
17
test/connection-manager/utils/connect-all.js
Normal 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
|
||||
)
|
||||
}
|
50
test/connection-manager/utils/create-libp2p-node.js
Normal file
50
test/connection-manager/utils/create-libp2p-node.js
Normal 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
|
83
test/connection-manager/utils/prepare.js
Normal file
83
test/connection-manager/utils/prepare.js
Normal 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)
|
||||
}
|
||||
}
|
27
test/connection-manager/utils/try-connect-all.js
Normal file
27
test/connection-manager/utils/try-connect-all.js
Normal 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
|
||||
)
|
||||
}
|
@@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
15
test/identify/basic.spec.js
Normal file
15
test/identify/basic.spec.js
Normal 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')
|
||||
})
|
||||
})
|
192
test/identify/dialer.spec.js
Normal file
192
test/identify/dialer.spec.js
Normal 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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
70
test/identify/listener.spec.js
Normal file
70
test/identify/listener.spec.js
Normal 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)
|
||||
})
|
||||
})
|
@@ -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
3
test/ping/node.js
Normal file
@@ -0,0 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
require('./test-ping.js')
|
118
test/ping/test-ping.js
Normal file
118
test/ping/test-ping.js
Normal 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)
|
||||
})
|
||||
})
|
5
test/pnet/fixtures/peer-a.json
Normal file
5
test/pnet/fixtures/peer-a.json
Normal 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="
|
||||
}
|
5
test/pnet/fixtures/peer-b.json
Normal file
5
test/pnet/fixtures/peer-b.json
Normal 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
105
test/pnet/pnet.spec.js
Normal 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)
|
||||
})
|
||||
})
|
||||
})
|
@@ -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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@@ -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()
|
||||
})
|
||||
|
||||
|
@@ -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')
|
||||
})
|
||||
})
|
@@ -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()
|
||||
|
@@ -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')
|
||||
|
Reference in New Issue
Block a user