Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"cids": "~0.5.7",
"debug": "^4.1.1",
"length-prefixed-stream": "github:jacobheun/length-prefixed-stream#v2.0.0-rc.1",
"libp2p": "~0.24.4",
"libp2p": "~0.25.0-rc.5",
"libp2p-bootstrap": "~0.9.7",
"libp2p-kad-dht": "~0.14.3",
"libp2p-mplex": "~0.8.4",
Expand Down
40 changes: 40 additions & 0 deletions src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { multiaddrToNetConfig } = require('./util')
const {
Request,
DHTRequest,
PeerstoreRequest,
PSRequest,
Response,
DHTResponse,
Expand Down Expand Up @@ -215,6 +216,36 @@ class Daemon {
})
}

async handlePeerstoreRequest ({ peerStore }, enc) {
switch (peerStore.type) {
case PeerstoreRequest.Type.GET_PROTOCOLS: {
let protos
try {
const peerId = PeerId.createFromBytes(peerStore.id)
const peerInfo = this.libp2p.peerBook.get(peerId)
protos = Array.from(peerInfo.protocols)
} catch (err) {
throw new Error('ERR_INVALID_PEERSTORE_REQUEST')
}

await new Promise((resolve) => {
enc.write(
OkResponse({
peerStore: { protos }
}),
resolve)
})
break
}
case PeerstoreRequest.Type.GET_PEER_INFO: {
throw new Error('ERR_NOT_IMPLEMENTED')
}
default: {
throw new Error('ERR_INVALID_REQUEST_TYPE')
}
}
}

/**
* Parses and responds to PSRequests
*
Expand Down Expand Up @@ -486,6 +517,15 @@ class Daemon {
enc.write(OkResponse())
break
}
case Request.Type.PEERSTORE: {
try {
await this.handlePeerstoreRequest(request, enc)
} catch (err) {
enc.write(ErrorResponse(err.message))
break
}
break
}
case Request.Type.PUBSUB: {
try {
await this.handlePubsubRequest(request, enc)
Expand Down
2 changes: 1 addition & 1 deletion src/libp2p.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,10 @@ const createLibp2p = async ({
}
},
dht: {
enabled: dht,
kBucketSize: 20
},
EXPERIMENTAL: {
dht: dht,
pubsub: pubsub
}
}
Expand Down
29 changes: 25 additions & 4 deletions src/protocol/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ message Request {
CONNMANAGER = 6;
DISCONNECT = 7;
PUBSUB = 8;
PEERSTORE = 9;
}

required Type type = 1;
Expand All @@ -24,6 +25,7 @@ message Request {
optional ConnManagerRequest connManager = 6;
optional DisconnectRequest disconnect = 7;
optional PSRequest pubsub = 8;
optional PeerstoreRequest peerStore = 9;
}

message Response {
Expand All @@ -39,6 +41,7 @@ message Response {
optional DHTResponse dht = 5;
repeated PeerInfo peers = 6;
optional PSResponse pubsub = 7;
optional PeerstoreResponse peerStore = 8;
}

message IdentifyResponse {
Expand All @@ -49,11 +52,13 @@ message IdentifyResponse {
message ConnectRequest {
required bytes peer = 1;
repeated bytes addrs = 2;
optional int64 timeout = 3;
}

message StreamOpenRequest {
required bytes peer = 1;
repeated string proto = 2;
optional int64 timeout = 3;
}

message StreamHandlerRequest {
Expand Down Expand Up @@ -87,7 +92,7 @@ message DHTRequest {
required Type type = 1;
optional bytes peer = 2;
optional bytes cid = 3;
optional string key = 4;
optional bytes key = 4;
optional bytes value = 5;
optional int32 count = 6;
optional int64 timeout = 7;
Expand All @@ -112,9 +117,9 @@ message PeerInfo {

message ConnManagerRequest {
enum Type {
TAG_PEER = 0;
UNTAG_PEER = 1;
TRIM = 2;
TAG_PEER = 0;
UNTAG_PEER = 1;
TRIM = 2;
}

required Type type = 1;
Expand Down Expand Up @@ -154,4 +159,20 @@ message PSResponse {
repeated string topics = 1;
repeated bytes peerIDs = 2;
}

message PeerstoreRequest {
enum Type {
GET_PROTOCOLS = 1;
GET_PEER_INFO = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the remaining types of PeerstoreRequest?

libp2p/go-libp2p-daemon#91/files#diff-d864c93b68284fafd809efbf29a1f0ebR166

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I noticed that you have only implemented GET_PROTOCOLS here.

Can I recommend adding the other ones and then throw a ERR_NOT_IMPLEMENTED for that? Moreover, can you create an issue for tracking the remaining ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll create an issue for when the spec gets done. I only added these initial two, as those likely won't change, but since the spec is still being discussed it didn't make sense to me to pull in a bunch of theoretical types.

I'll add ERR_NOT_IMPLEMENTED for the types that are currently in the proto file.

}

required Type type = 1;
optional bytes id = 2;
repeated string protos = 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are also missing some properties here and in the response.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only added the required properties for the two types that are here. The rest should be added once the spec is merged for the other types.

}

message PeerstoreResponse {
optional PeerInfo peer = 1;
repeated string protos = 2;
}
`)
128 changes: 128 additions & 0 deletions test/daemon/peerstore.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ['error', 5] */
'use strict'

const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const os = require('os')
const path = require('path')
const ma = require('multiaddr')
const { createDaemon } = require('../../src/daemon')
const Client = require('../../src/client')
const { createLibp2p } = require('../../src/libp2p')
const { isWindows } = require('../../src/util')
const { connect } = require('../util')
const {
Request,
Response,
PeerstoreRequest
} = require('../../src/protocol')

const daemonAddr = isWindows
? ma('/ip4/0.0.0.0/tcp/8080')
: ma(`/unix${path.resolve(os.tmpdir(), '/tmp/p2pd.sock')}`)

describe('peerstore features', () => {
let daemon
let libp2pPeer
let client

before(async function () {
// this.timeout(20e3)
daemon = await createDaemon({
quiet: false,
q: false,
bootstrap: false,
hostAddrs: '/ip4/0.0.0.0/tcp/0,/ip4/0.0.0.0/tcp/0/ws',
b: false,
dht: true,
dhtClient: false,
connMgr: false,
listen: daemonAddr.toString(),
id: '',
bootstrapPeers: ''
})
libp2pPeer = await createLibp2p({
dht: true,
hostAddrs: '/ip4/0.0.0.0/tcp/0'
})

await Promise.all([
daemon.start(),
libp2pPeer.start()
])

await connect({
libp2pPeer,
multiaddr: daemonAddr
})
})

before(async () => {
await new Promise(resolve => setTimeout(resolve, 1e3))
})

after(() => {
return Promise.all([
daemon.stop(),
libp2pPeer.stop()
])
})

afterEach(async () => {
await client && client.close()
})

it('should be able to get the protocols for a peer', async () => {
client = new Client(daemonAddr)

await client.attach()

const request = {
type: Request.Type.PEERSTORE,
peerStore: {
type: PeerstoreRequest.Type.GET_PROTOCOLS,
id: Buffer.from(libp2pPeer.peerInfo.id.toBytes())
}
}

const stream = client.send(request)

const message = await stream.first()
let response = Response.decode(message)
expect(response.type).to.eql(Response.Type.OK)
expect(response.peerStore).to.eql({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not expect(response.peerStore.protos) instead?

peer: null is not part of the spec, and we could potentially accept anything else there in the future, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

peer is a response field for GET_PEER_INFO, which is currently not implemented. I'm validating the full response to ensure that no additional fields are being "leaked"/accidentally set in the response. While expect(response.peerStore.protos) verifies I am getting the correct protocols, it doesn't fully verify I am getting the expected response.

protos: [
'/mplex/6.7.0',
'/ipfs/id/1.0.0',
'/ipfs/ping/1.0.0',
'/libp2p/circuit/relay/0.1.0',
'/ipfs/kad/1.0.0'
],
peer: null
})
stream.end()
})

it('NOT IMPLEMENTED get peer info', async () => {
client = new Client(daemonAddr)

await client.attach()

const request = {
type: Request.Type.PEERSTORE,
peerStore: {
type: PeerstoreRequest.Type.GET_PEER_INFO,
id: Buffer.from(libp2pPeer.peerInfo.id.toBytes())
}
}

const stream = client.send(request)

const message = await stream.first()
let response = Response.decode(message)
expect(response.type).to.eql(Response.Type.ERROR)
expect(response.error.msg).to.eql('ERR_NOT_IMPLEMENTED')
})
})
14 changes: 11 additions & 3 deletions test/protocol.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe('protocol', () => {
peer: Buffer.from('QmTarget'),
addrs: [
multiaddr('/ip4/0.0.0.0/tcp/0').buffer
]
],
timeout: 0
}
const request = {
type: Request.Type.CONNECT,
Expand All @@ -29,6 +30,7 @@ describe('protocol', () => {
streamHandler: null,
dht: null,
disconnect: null,
peerStore: null,
pubsub: null,
connManager: null
}
Expand All @@ -40,7 +42,8 @@ describe('protocol', () => {
it('should be able to encode/decode a StreamOpenRequest', () => {
const streamOpenRequest = {
peer: Buffer.from('QmTarget'),
proto: ['/p2pdaemon/1.0.0']
proto: ['/p2pdaemon/1.0.0'],
timeout: 0
}
const request = {
type: Request.Type.STREAM_OPEN,
Expand All @@ -49,6 +52,7 @@ describe('protocol', () => {
streamHandler: null,
dht: null,
disconnect: null,
peerStore: null,
pubsub: null,
connManager: null
}
Expand All @@ -69,6 +73,7 @@ describe('protocol', () => {
streamHandler: streamHandlerRequest,
dht: null,
disconnect: null,
peerStore: null,
pubsub: null,
connManager: null
}
Expand All @@ -82,7 +87,7 @@ describe('protocol', () => {
type: DHTRequest.Type.FIND_PEER,
peer: Buffer.from('QmTarget'),
cid: null,
key: '',
key: Buffer.alloc(0),
value: null,
count: 0,
timeout: 0
Expand All @@ -94,6 +99,7 @@ describe('protocol', () => {
streamHandler: null,
dht: dhtRequest,
disconnect: null,
peerStore: null,
pubsub: null,
connManager: null
}
Expand All @@ -116,6 +122,7 @@ describe('protocol', () => {
streamHandler: null,
dht: null,
disconnect: null,
peerStore: null,
pubsub: null,
connManager: connManagerRequest
}
Expand All @@ -136,6 +143,7 @@ describe('protocol', () => {
identify: null,
dht: null,
pubsub: null,
peerStore: null,
peers: []
}
const message = Response.encode(response)
Expand Down