Skip to content

Commit 53b1645

Browse files
saul-jbachingbrain
andauthored
feat: add support for arbitrary service modules (#1563)
Updates the libp2p init args to accept an object of service factory functions that can use internal libp2p components. The returned libp2p object has a `.services` key that corresponds to the service factory keys. --------- Co-authored-by: achingbrain <[email protected]>
1 parent ba47c95 commit 53b1645

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2066
-2002
lines changed

.aegir.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ export default {
1717
const { plaintext } = await import('./dist/src/insecure/index.js')
1818
const { default: Peers } = await import('./dist/test/fixtures/peers.js')
1919
const { circuitRelayServer, circuitRelayTransport } = await import('./dist/src/circuit-relay/index.js')
20+
const { identifyService } = await import('./dist/src/identify/index.js')
21+
const { pingService } = await import('./dist/src/ping/index.js')
22+
const { fetchService } = await import('./dist/src/fetch/index.js')
2023

2124
// Use the last peer
2225
const peerId = await createFromJSON(Peers[Peers.length - 1])
@@ -39,9 +42,15 @@ export default {
3942
noise(),
4043
plaintext()
4144
],
42-
relay: circuitRelayServer(),
43-
nat: {
44-
enabled: false
45+
services: {
46+
identify: identifyService(),
47+
ping: pingService(),
48+
fetch: fetchService(),
49+
relay: circuitRelayServer({
50+
reservations: {
51+
maxReservations: Infinity
52+
}
53+
})
4554
}
4655
})
4756
// Add the echo protocol

doc/CONFIGURATION.md

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
- [Configuring Metrics](#configuring-metrics)
3131
- [Configuring PeerStore](#configuring-peerstore)
3232
- [Customizing Transports](#customizing-transports)
33-
- [Configuring the NAT Manager](#configuring-the-nat-manager)
33+
- [Configuring UPnP NAT Traversal](#configuring-upnp-nat-traversal)
3434
- [Browser support](#browser-support)
3535
- [UPnP and NAT-PMP](#upnp-and-nat-pmp)
3636
- [Configuring protocol name](#configuring-protocol-name)
@@ -142,8 +142,9 @@ Some available content routing modules are:
142142

143143
- [@libp2p/kad-dht](https://github.com/libp2p/js-libp2p-kad-dht)
144144
- [@libp2p/delegated-content-routing](https://github.com/libp2p/js-libp2p-delegated-content-routing)
145+
- [@libp2p/ipni-content-routing](https://github.com/libp2p/js-ipni-content-routing)
145146

146-
If none of the available content routing protocols fulfills your needs, you can create a libp2p compatible one. A libp2p content routing protocol just needs to be compliant with the [Content Routing Interface](https://github.com/libp2p/js-interfaces/tree/master/src/content-routing). **(WIP: This module is not yet implemented)**
147+
If none of the available content routing protocols fulfil your needs, you can create a libp2p compatible one. A libp2p content routing protocol just needs to be compliant with the [Content Routing Interface](https://github.com/libp2p/js-interfaces/tree/master/src/content-routing).
147148

148149
If you want to know more about libp2p content routing, you should read the following content:
149150

@@ -205,8 +206,9 @@ const modules = {
205206
contentRouting: [],
206207
peerRouting: [],
207208
peerDiscovery: [],
208-
dht: dhtImplementation,
209-
pubsub: pubsubImplementation
209+
services: {
210+
serviceKey: serviceImplementation
211+
}
210212
}
211213
```
212214

@@ -252,8 +254,10 @@ const node = await createLibp2p({
252254
streamMuxers: [mplex()],
253255
connectionEncryption: [noise()],
254256
peerDiscovery: [MulticastDNS],
255-
dht: kadDHT(),
256-
pubsub: gossipsub()
257+
services: {
258+
dht: kadDHT(),
259+
pubsub: gossipsub()
260+
}
257261
})
258262
```
259263

@@ -335,10 +339,12 @@ const node = await createLibp2p({
335339
connectionEncryption: [
336340
noise()
337341
],
338-
pubsub: gossipsub({
339-
emitSelf: false, // whether the node should emit to self on publish
340-
globalSignaturePolicy: SignaturePolicy.StrictSign // message signing policy
341-
})
342+
services: {
343+
pubsub: gossipsub({
344+
emitSelf: false, // whether the node should emit to self on publish
345+
globalSignaturePolicy: SignaturePolicy.StrictSign // message signing policy
346+
})
347+
}
342348
}
343349
})
344350
```
@@ -362,10 +368,12 @@ const node = await createLibp2p({
362368
connectionEncryption: [
363369
noise()
364370
],
365-
dht: kadDHT({
366-
kBucketSize: 20,
367-
clientMode: false // Whether to run the WAN DHT in client or server mode (default: client mode)
368-
})
371+
services: {
372+
dht: kadDHT({
373+
kBucketSize: 20,
374+
clientMode: false // Whether to run the WAN DHT in client or server mode (default: client mode)
375+
})
376+
}
369377
})
370378
```
371379

@@ -435,21 +443,6 @@ const node = await createLibp2p({
435443
],
436444
streamMuxers: [mplex()],
437445
connectionEncryption: [noise()],
438-
relay: circuitRelayServer({ // makes the node function as a relay server
439-
hopTimeout: 30 * 1000, // incoming relay requests must be resolved within this time limit
440-
advertise: { // if set, use content routing to broadcast availability of this relay
441-
bootDelay: 30 * 1000 // how long to wait after startup before broadcast
442-
},
443-
reservations: {
444-
maxReservations: 15 // how many peers are allowed to reserve relay slots on this server
445-
reservationClearInterval: 300 * 1000 // how often to reclaim stale reservations
446-
applyDefaultLimit: true // whether to apply default data/duration limits to each relayed connection
447-
defaultDurationLimit: 2 * 60 * 1000 // the default maximum amount of time a relayed connection can be open for
448-
defaultDataLimit: BigInt(2 << 7) // the default maximum number of bytes that can be transferred over a relayed connection
449-
maxInboundHopStreams: 32 // how many inbound HOP streams are allow simultaneously
450-
maxOutboundHopStreams: 64 // how many outbound HOP streams are allow simultaneously
451-
}
452-
}),
453446
connectionGater: {
454447
// used by the server - return true to deny a reservation to the remote peer
455448
denyInboundRelayReservation: (source: PeerId) => Promise<boolean>
@@ -459,6 +452,23 @@ const node = await createLibp2p({
459452

460453
// used by the client - return true to deny a relay connection from the remote relay and peer
461454
denyInboundRelayedConnection: (relay: PeerId, remotePeer: PeerId) => Promise<boolean>
455+
},
456+
services: {
457+
relay: circuitRelayServer({ // makes the node function as a relay server
458+
hopTimeout: 30 * 1000, // incoming relay requests must be resolved within this time limit
459+
advertise: { // if set, use content routing to broadcast availability of this relay
460+
bootDelay: 30 * 1000 // how long to wait after startup before broadcast
461+
},
462+
reservations: {
463+
maxReservations: 15 // how many peers are allowed to reserve relay slots on this server
464+
reservationClearInterval: 300 * 1000 // how often to reclaim stale reservations
465+
applyDefaultLimit: true // whether to apply default data/duration limits to each relayed connection
466+
defaultDurationLimit: 2 * 60 * 1000 // the default maximum amount of time a relayed connection can be open for
467+
defaultDataLimit: BigInt(2 << 7) // the default maximum number of bytes that can be transferred over a relayed connection
468+
maxInboundHopStreams: 32 // how many inbound HOP streams are allow simultaneously
469+
maxOutboundHopStreams: 64 // how many outbound HOP streams are allow simultaneously
470+
}
471+
}),
462472
}
463473
})
464474
```
@@ -844,24 +854,28 @@ const node = await createLibp2p({
844854
})
845855
```
846856

847-
#### Configuring the NAT Manager
857+
#### Configuring UPnP NAT Traversal
848858

849859
Network Address Translation (NAT) is a function performed by your router to enable multiple devices on your local network to share a single IPv4 address. It's done transparently for outgoing connections, ensuring the correct response traffic is routed to your computer, but if you wish to accept incoming connections some configuration is necessary.
850860

851-
The NAT manager can be configured as follows:
861+
Some home routers support [UPnP NAT](https://en.wikipedia.org/wiki/Universal_Plug_and_Play) which allows network devices to request traffic to be forwarded from public facing ports that would otherwise be firewalled.
862+
863+
If your router supports this, libp2p can be configured to use it as follows:
852864

853865
```js
866+
import { createLibp2p } from 'libp2p'
867+
import { uPnPNAT } from 'libp2p/upnp-nat'
868+
854869
const node = await createLibp2p({
855-
config: {
856-
nat: {
857-
enabled: true, // defaults to true
870+
services: {
871+
nat: uPnPNAT({
858872
description: 'my-node', // set as the port mapping description on the router, defaults the current libp2p version and your peer id
859873
gateway: '192.168.1.1', // leave unset to auto-discover
860874
externalIp: '80.1.1.1', // leave unset to auto-discover
861875
localAddress: '129.168.1.123', // leave unset to auto-discover
862876
ttl: 7200, // TTL for port mappings (min 20 minutes)
863877
keepAlive: true, // Refresh port mapping after TTL expires
864-
}
878+
})
865879
}
866880
})
867881
```
@@ -881,12 +895,18 @@ By default under nodejs libp2p will attempt to use [UPnP](https://en.wikipedia.o
881895
Changing the protocol name prefix can isolate default public network (IPFS) for custom purposes.
882896

883897
```js
898+
import { createLibp2p } from 'libp2p'
899+
import { identifyService } from 'libp2p/identify'
900+
import { pingService } from 'libp2p/ping'
901+
884902
const node = await createLibp2p({
885-
identify: {
886-
protocolPrefix: 'ipfs' // default
887-
},
888-
ping: {
889-
protocolPrefix: 'ipfs' // default
903+
services: {
904+
identify: identifyService({
905+
protocolPrefix: 'ipfs' // default
906+
}),
907+
ping: pingService({
908+
protocolPrefix: 'ipfs' // default
909+
})
890910
}
891911
})
892912
/*

doc/LIMITS.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ We can also limit the number of connections in a "pending" state. These connecti
2929
All fields are optional. The default values are defined in [src/connection-manager/index.ts](https://github.com/libp2p/js-libp2p/blob/master/src/connection-manager/index.ts) - please see that file for the current values.
3030

3131
```ts
32-
const node = await createLibp2pNode({
32+
const node = await createLibp2p({
3333
connectionManager: {
3434
/**
3535
* The total number of connections allowed to be open at one time
@@ -69,7 +69,7 @@ To prevent individual peers from opening multiple connections to a node, an `inb
6969
All fields are optional. The default values are defined in [src/connection-manager/index.ts](https://github.com/libp2p/js-libp2p/blob/master/src/connection-manager/index.ts) - please see that file for the current values.
7070

7171
```ts
72-
const node = await createLibp2pNode({
72+
const node = await createLibp2p({
7373
connectionManager: {
7474
/**
7575
* A remote peer may attempt to open up to this many connections per second,
@@ -93,7 +93,7 @@ These settings are done on a per-muxer basis, please see the README of the relev
9393
All fields are optional. The default values are defined in [@libp2p/mplex/src/mplex.ts](https://github.com/libp2p/js-libp2p-mplex/blob/master/src/mplex.ts) - please see that file for the current values.
9494

9595
```ts
96-
const node = await createLibp2pNode({
96+
const node = await createLibp2p({
9797
muxers: [
9898
mplex({
9999
/**
@@ -133,7 +133,7 @@ const node = await createLibp2pNode({
133133
All fields are optional. The default values are defined in [@chainsafe/libp2p-yamux/src/config.ts](https://github.com/ChainSafe/js-libp2p-yamux/blob/master/src/config.ts) - please see that file for the current values.
134134

135135
```ts
136-
const node = await createLibp2pNode({
136+
const node = await createLibp2p({
137137
muxers: [
138138
yamux({
139139
/**
@@ -186,7 +186,7 @@ The [@libp2p/tcp](https://github.com/libp2p/js-libp2p-tcp) transport allows addi
186186
All fields are optional. The full list of options is defined in [@libp2p/tcp/src/index.ts](https://github.com/libp2p/js-libp2p-tcp/blob/master/src/index.ts) - please see that file for more details.
187187

188188
```ts
189-
const node = await createLibp2pNode({
189+
const node = await createLibp2p({
190190
transports: [
191191
tcp({
192192
/**
@@ -215,7 +215,7 @@ const node = await createLibp2pNode({
215215
It is possible to configure some hosts to always accept connections from and some to always reject connections from.
216216

217217
```js
218-
const node = await createLibp2pNode({
218+
const node = await createLibp2p({
219219
connectionManager: {
220220
/**
221221
* A list of multiaddrs, any connection with a `remoteAddress` property

doc/METRICS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ Although designed to primarily integrate with tools such as [Prometheus](https:/
3232
First enable metrics tracking by supplying a [Metrics](https://www.npmjs.com/package/@libp2p/interface-metrics) implementation:
3333

3434
```js
35-
import { createLibp2pNode } from 'libp2p'
35+
import { createLibp2p } from 'libp2p'
3636
import { prometheusMetrics } from '@libp2p/prometheus-metrics'
3737

38-
const node = await createLibp2pNode({
38+
const node = await createLibp2p({
3939
metrics: prometheusMetrics()
4040
//... other config
4141
})
@@ -164,7 +164,7 @@ Metrics implementations will allow extracting the values for presentation in an
164164
import { prometheusMetrics } from '@libp2p/prometheus-metrics'
165165
import client from 'prom-client'
166166

167-
const libp2p = createLibp2pNode({
167+
const libp2p = createLibp2p({
168168
metrics: prometheusMetrics()
169169
//... other config
170170
})

doc/migrations/v0.44-v0.45.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ A migration guide for refactoring your application code from libp2p v0.44.x to v
44

55
## Table of Contents <!-- omit in toc -->
66

7+
- [Services](#services)
78
- [Events](#events)
89
- [Emitters](#emitters)
910
- [Event changes](#event-changes)
@@ -13,6 +14,75 @@ A migration guide for refactoring your application code from libp2p v0.44.x to v
1314
- [`self:peer:update`](#selfpeerupdate)
1415
- [Atomic peer store methods](#atomic-peer-store-methods)
1516

17+
## Services
18+
19+
libp2p now accepts arbitrary service modules that can use internal components to fulfil their functions.
20+
21+
This reduces the attack surface area of libp2p nodes as less functionality is enabled by default, and with tree shaking less code will be included in bundles making for faster downloads when used in browsers.
22+
23+
Several optional modules have been removed and must now be configured as services:
24+
25+
**Before**
26+
27+
```js
28+
import { createLibp2p } from 'libp2p'
29+
import { circuitRelayServer } from 'libp2p/circuit-relay'
30+
import { kadDHT } from '@libp2p/kad-dht'
31+
import { gossipSub } from '@ChainSafe/libp2p-gossipsub'
32+
33+
const node = createLibp2p({
34+
// ... other options here
35+
identify: {
36+
/** identify options **/
37+
},
38+
ping: {
39+
/** ping options **/
40+
},
41+
fetch: {
42+
/** fetch options **/
43+
},
44+
pubsub: gossipSub(),
45+
dht: kadDHT(),
46+
relay: circuitRelayServer()
47+
})
48+
```
49+
50+
**After**
51+
52+
```js
53+
import { createLibp2p } from 'libp2p'
54+
import { circuitRelayServer } from 'libp2p/circuit-relay'
55+
import { identifyService } from 'libp2p/identify'
56+
import { pingService } from 'libp2p/ping'
57+
import { fetchService } from 'libp2p/fetch'
58+
import { kadDHT } from '@libp2p/kad-dht'
59+
import { gossipSub } from '@ChainSafe/libp2p-gossipsub'
60+
61+
const node = createLibp2p({
62+
// ... other options here
63+
services: {
64+
identify: identifyService({
65+
/** identify options **/
66+
}),
67+
ping: pingService({
68+
/** ping options **/
69+
}),
70+
fetch: fetchService({
71+
/** fetch options **/
72+
}),
73+
pubsub: gossipSub(),
74+
dht: kadDHT(),
75+
relay: circuitRelayServer()
76+
}
77+
})
78+
```
79+
80+
Configured services can be accessed via the `.services` key:
81+
82+
```js
83+
const result = await node.services.ping.ping(multiaddr('...'))
84+
```
85+
1686
## Events
1787

1888
The events emitted by libp2p have been refactored to be more consistent and to give more insight into the inner workings of libp2p.

examples/auto-relay/dialer.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { noise } from '@chainsafe/libp2p-noise'
44
import { mplex } from '@libp2p/mplex'
55
import { multiaddr } from '@multiformats/multiaddr'
66
import { circuitRelayTransport } from 'libp2p/circuit-relay'
7+
import { identifyService } from 'libp2p/identify'
78

89
async function main () {
910
const autoRelayNodeAddr = process.argv[2]
@@ -21,7 +22,10 @@ async function main () {
2122
],
2223
streamMuxers: [
2324
mplex()
24-
]
25+
],
26+
services: {
27+
identify: identifyService()
28+
}
2529
})
2630

2731
console.log(`Node started with id ${node.peerId.toString()}`)

0 commit comments

Comments
 (0)