Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for arbitrary service modules #1563

Merged
merged 6 commits into from
Apr 29, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
15 changes: 12 additions & 3 deletions .aegir.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export default {
const { plaintext } = await import('./dist/src/insecure/index.js')
const { default: Peers } = await import('./dist/test/fixtures/peers.js')
const { circuitRelayServer, circuitRelayTransport } = await import('./dist/src/circuit-relay/index.js')
const { identifyService } = await import('./dist/src/identify/index.js')
const { pingService } = await import('./dist/src/ping/index.js')
const { fetchService } = await import('./dist/src/fetch/index.js')

// Use the last peer
const peerId = await createFromJSON(Peers[Peers.length - 1])
Expand All @@ -39,9 +42,15 @@ export default {
noise(),
plaintext()
],
relay: circuitRelayServer(),
nat: {
enabled: false
services: {
identify: identifyService(),
ping: pingService(),
fetch: fetchService(),
relay: circuitRelayServer({
reservations: {
maxReservations: Infinity
maschad marked this conversation as resolved.
Show resolved Hide resolved
}
})
}
})
// Add the echo protocol
Expand Down
100 changes: 60 additions & 40 deletions doc/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
- [Configuring Metrics](#configuring-metrics)
- [Configuring PeerStore](#configuring-peerstore)
- [Customizing Transports](#customizing-transports)
- [Configuring the NAT Manager](#configuring-the-nat-manager)
- [Configuring UPnP NAT Traversal](#configuring-upnp-nat-traversal)
- [Browser support](#browser-support)
- [UPnP and NAT-PMP](#upnp-and-nat-pmp)
- [Configuring protocol name](#configuring-protocol-name)
Expand Down Expand Up @@ -142,8 +142,9 @@ Some available content routing modules are:

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

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)**
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).

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

Expand Down Expand Up @@ -205,8 +206,9 @@ const modules = {
contentRouting: [],
peerRouting: [],
peerDiscovery: [],
dht: dhtImplementation,
pubsub: pubsubImplementation
services: {
serviceKey: serviceImplementation
}
}
```

Expand Down Expand Up @@ -252,8 +254,10 @@ const node = await createLibp2p({
streamMuxers: [mplex()],
connectionEncryption: [noise()],
peerDiscovery: [MulticastDNS],
dht: kadDHT(),
pubsub: gossipsub()
services: {
dht: kadDHT(),
pubsub: gossipsub()
}
})
```

Expand Down Expand Up @@ -335,10 +339,12 @@ const node = await createLibp2p({
connectionEncryption: [
noise()
],
pubsub: gossipsub({
emitSelf: false, // whether the node should emit to self on publish
globalSignaturePolicy: SignaturePolicy.StrictSign // message signing policy
})
services: {
pubsub: gossipsub({
emitSelf: false, // whether the node should emit to self on publish
globalSignaturePolicy: SignaturePolicy.StrictSign // message signing policy
})
}
}
})
```
Expand All @@ -362,10 +368,12 @@ const node = await createLibp2p({
connectionEncryption: [
noise()
],
dht: kadDHT({
kBucketSize: 20,
clientMode: false // Whether to run the WAN DHT in client or server mode (default: client mode)
})
services: {
dht: kadDHT({
kBucketSize: 20,
clientMode: false // Whether to run the WAN DHT in client or server mode (default: client mode)
})
}
})
```

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

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

#### Configuring the NAT Manager
#### Configuring UPnP NAT Traversal

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.

The NAT manager can be configured as follows:
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.

If your router supports this, libp2p can be configured to use it as follows:

```js
import { createLibp2p } from 'libp2p'
import { uPnPNAT } from 'libp2p/upnp-nat'

const node = await createLibp2p({
config: {
nat: {
enabled: true, // defaults to true
services: {
nat: uPnPNAT({
description: 'my-node', // set as the port mapping description on the router, defaults the current libp2p version and your peer id
gateway: '192.168.1.1', // leave unset to auto-discover
externalIp: '80.1.1.1', // leave unset to auto-discover
localAddress: '129.168.1.123', // leave unset to auto-discover
ttl: 7200, // TTL for port mappings (min 20 minutes)
keepAlive: true, // Refresh port mapping after TTL expires
}
})
}
})
```
Expand All @@ -881,12 +895,18 @@ By default under nodejs libp2p will attempt to use [UPnP](https://en.wikipedia.o
Changing the protocol name prefix can isolate default public network (IPFS) for custom purposes.

```js
import { createLibp2p } from 'libp2p'
import { identifyService } from 'libp2p/identify'
import { pingService } from 'libp2p/ping'

const node = await createLibp2p({
identify: {
protocolPrefix: 'ipfs' // default
},
ping: {
protocolPrefix: 'ipfs' // default
services: {
identify: identifyService({
protocolPrefix: 'ipfs' // default
}),
ping: pingService({
protocolPrefix: 'ipfs' // default
})
}
})
/*
Expand Down
12 changes: 6 additions & 6 deletions doc/LIMITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ We can also limit the number of connections in a "pending" state. These connecti
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.

```ts
const node = await createLibp2pNode({
const node = await createLibp2p({
connectionManager: {
/**
* The total number of connections allowed to be open at one time
Expand Down Expand Up @@ -69,7 +69,7 @@ To prevent individual peers from opening multiple connections to a node, an `inb
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.

```ts
const node = await createLibp2pNode({
const node = await createLibp2p({
connectionManager: {
/**
* A remote peer may attempt to open up to this many connections per second,
Expand All @@ -93,7 +93,7 @@ These settings are done on a per-muxer basis, please see the README of the relev
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.

```ts
const node = await createLibp2pNode({
const node = await createLibp2p({
muxers: [
mplex({
/**
Expand Down Expand Up @@ -133,7 +133,7 @@ const node = await createLibp2pNode({
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.

```ts
const node = await createLibp2pNode({
const node = await createLibp2p({
muxers: [
yamux({
/**
Expand Down Expand Up @@ -186,7 +186,7 @@ The [@libp2p/tcp](https://github.com/libp2p/js-libp2p-tcp) transport allows addi
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.

```ts
const node = await createLibp2pNode({
const node = await createLibp2p({
transports: [
tcp({
/**
Expand Down Expand Up @@ -215,7 +215,7 @@ const node = await createLibp2pNode({
It is possible to configure some hosts to always accept connections from and some to always reject connections from.

```js
const node = await createLibp2pNode({
const node = await createLibp2p({
connectionManager: {
/**
* A list of multiaddrs, any connection with a `remoteAddress` property
Expand Down
6 changes: 3 additions & 3 deletions doc/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ Although designed to primarily integrate with tools such as [Prometheus](https:/
First enable metrics tracking by supplying a [Metrics](https://www.npmjs.com/package/@libp2p/interface-metrics) implementation:

```js
import { createLibp2pNode } from 'libp2p'
import { createLibp2p } from 'libp2p'
import { prometheusMetrics } from '@libp2p/prometheus-metrics'

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

const libp2p = createLibp2pNode({
const libp2p = createLibp2p({
metrics: prometheusMetrics()
//... other config
})
Expand Down
70 changes: 70 additions & 0 deletions doc/migrations/v0.44-v0.45.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ A migration guide for refactoring your application code from libp2p v0.44.x to v

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

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

## Services

libp2p now accepts arbitrary service modules that can use internal components to fulfil their functions.

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.

Several optional modules have been removed and must now be configured as services:

**Before**

```js
import { createLibp2p } from 'libp2p'
import { circuitRelayServer } from 'libp2p/circuit-relay'
import { kadDHT } from '@libp2p/kad-dht'
import { gossipSub } from '@ChainSafe/libp2p-gossipsub'

const node = createLibp2p({
// ... other options here
identify: {
/** identify options **/
},
ping: {
/** ping options **/
},
fetch: {
/** fetch options **/
},
pubsub: gossipSub(),
dht: kadDHT(),
relay: circuitRelayServer()
})
```

**After**

```js
import { createLibp2p } from 'libp2p'
import { circuitRelayServer } from 'libp2p/circuit-relay'
import { identifyService } from 'libp2p/identify'
import { pingService } from 'libp2p/ping'
import { fetchService } from 'libp2p/fetch'
import { kadDHT } from '@libp2p/kad-dht'
import { gossipSub } from '@ChainSafe/libp2p-gossipsub'

const node = createLibp2p({
// ... other options here
services: {
identify: identifyService({
/** identify options **/
}),
ping: pingService({
/** ping options **/
}),
fetch: fetchService({
/** fetch options **/
}),
pubsub: gossipSub(),
dht: kadDHT(),
relay: circuitRelayServer()
}
})
```

Configured services can be accessed via the `.services` key:

```js
const result = await node.services.ping.ping(multiaddr('...'))
```

## Events

The events emitted by libp2p have been refactored to be more consistent and to give more insight into the inner workings of libp2p.
Expand Down
6 changes: 5 additions & 1 deletion examples/auto-relay/dialer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { noise } from '@chainsafe/libp2p-noise'
import { mplex } from '@libp2p/mplex'
import { multiaddr } from '@multiformats/multiaddr'
import { circuitRelayTransport } from 'libp2p/circuit-relay'
import { identifyService } from 'libp2p/identify'

async function main () {
const autoRelayNodeAddr = process.argv[2]
Expand All @@ -21,7 +22,10 @@ async function main () {
],
streamMuxers: [
mplex()
]
],
services: {
identify: identifyService()
}
})

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