Skip to content

Commit d5fbbe0

Browse files
vasco-santosjacobheun
authored andcommitted
feat: support dial only on transport manager to tolerate errors (#643)
* feat: support dial only on transport manager to tolerate errors * chore: address review * chore: add jsdoc to transport manager tolerance errors
1 parent 24a148f commit d5fbbe0

File tree

6 files changed

+109
-3
lines changed

6 files changed

+109
-3
lines changed

doc/API.md

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Creates an instance of Libp2p.
8989
| [options.addresses] | `{ listen: Array<string>, announce: Array<string>, noAnnounce: Array<string> }` | Addresses for transport listening and to advertise to the network |
9090
| [options.config] | `object` | libp2p modules configuration and core configuration |
9191
| [options.connectionManager] | [`object`](./CONFIGURATION.md#configuring-connection-manager) | libp2p Connection Manager configuration |
92+
| [options.transportManager] | [`object`](./CONFIGURATION.md#configuring-transport-manager) | libp2p transport manager configuration |
9293
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
9394
| [options.dialer] | [`object`](./CONFIGURATION.md#configuring-dialing) | libp2p Dialer configuration
9495
| [options.keychain] | [`object`](./CONFIGURATION.md#setup-with-keychain) | keychain configuration |

doc/CONFIGURATION.md

+25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- [Setup with Keychain](#setup-with-keychain)
2424
- [Configuring Dialing](#configuring-dialing)
2525
- [Configuring Connection Manager](#configuring-connection-manager)
26+
- [Configuring Transport Manager](#configuring-transport-manager)
2627
- [Configuring Metrics](#configuring-metrics)
2728
- [Configuring PeerStore](#configuring-peerstore)
2829
- [Customizing Transports](#customizing-transports)
@@ -517,6 +518,30 @@ const node = await Libp2p.create({
517518
})
518519
```
519520
521+
#### Configuring Transport Manager
522+
523+
The Transport Manager is responsible for managing the libp2p transports life cycle. This includes starting listeners for the provided listen addresses, closing these listeners and dialing using the provided transports. By default, if a libp2p node has a list of multiaddrs for listenning on and there are no valid transports for those multiaddrs, libp2p will throw an error on startup and shutdown. However, for some applications it is perfectly acceptable for libp2p nodes to start in dial only mode if all the listen multiaddrs failed. This error tolerance can be enabled as follows:
524+
525+
```js
526+
const Libp2p = require('libp2p')
527+
const TCP = require('libp2p-tcp')
528+
const MPLEX = require('libp2p-mplex')
529+
const SECIO = require('libp2p-secio')
530+
531+
const { FaultTolerance } = require('libp2p/src/transport-manager')}
532+
533+
const node = await Libp2p.create({
534+
modules: {
535+
transport: [TCP],
536+
streamMuxer: [MPLEX],
537+
connEncryption: [SECIO]
538+
},
539+
transportManager: {
540+
faultTolerance: FaultTolerance.NO_FATAL
541+
}
542+
})
543+
```
544+
520545
#### Configuring Metrics
521546
522547
Metrics are disabled in libp2p by default. You can enable and configure them as follows:

src/config.js

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
const mergeOptions = require('merge-options')
44
const Constants = require('./constants')
55

6+
const { FaultTolerance } = require('./transport-manager')
7+
68
const DefaultConfig = {
79
addresses: {
810
listen: [],
@@ -12,6 +14,9 @@ const DefaultConfig = {
1214
connectionManager: {
1315
minPeers: 25
1416
},
17+
transportManager: {
18+
faultTolerance: FaultTolerance.FATAL_ALL
19+
},
1520
dialer: {
1621
maxParallelDials: Constants.MAX_PARALLEL_DIALS,
1722
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,

src/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ class Libp2p extends EventEmitter {
101101
// Setup the transport manager
102102
this.transportManager = new TransportManager({
103103
libp2p: this,
104-
upgrader: this.upgrader
104+
upgrader: this.upgrader,
105+
faultTolerance: this._options.transportManager.faultTolerance
105106
})
106107

107108
// Create the Registrar

src/transport-manager.js

+22-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ class TransportManager {
1313
* @param {object} options
1414
* @param {Libp2p} options.libp2p The Libp2p instance. It will be passed to the transports.
1515
* @param {Upgrader} options.upgrader The upgrader to provide to the transports
16+
* @param {boolean} [options.faultTolerance = FAULT_TOLERANCE.FATAL_ALL] Address listen error tolerance.
1617
*/
17-
constructor ({ libp2p, upgrader }) {
18+
constructor ({ libp2p, upgrader, faultTolerance = FAULT_TOLERANCE.FATAL_ALL }) {
1819
this.libp2p = libp2p
1920
this.upgrader = upgrader
2021
this._transports = new Map()
2122
this._listeners = new Map()
23+
this.faultTolerance = faultTolerance
2224
}
2325

2426
/**
@@ -173,7 +175,11 @@ class TransportManager {
173175
// If no transports were able to listen, throw an error. This likely
174176
// means we were given addresses we do not have transports for
175177
if (couldNotListen.length === this._transports.size) {
176-
throw errCode(new Error(`no valid addresses were provided for transports [${couldNotListen}]`), codes.ERR_NO_VALID_ADDRESSES)
178+
const message = `no valid addresses were provided for transports [${couldNotListen}]`
179+
if (this.faultTolerance === FAULT_TOLERANCE.FATAL_ALL) {
180+
throw errCode(new Error(message), codes.ERR_NO_VALID_ADDRESSES)
181+
}
182+
log(`libp2p in dial mode only: ${message}`)
177183
}
178184
}
179185

@@ -212,4 +218,18 @@ class TransportManager {
212218
}
213219
}
214220

221+
/**
222+
* Enum Transport Manager Fault Tolerance values.
223+
* FATAL_ALL should be used for failing in any listen circumstance.
224+
* NO_FATAL should be used for not failing when not listening.
225+
* @readonly
226+
* @enum {number}
227+
*/
228+
const FAULT_TOLERANCE = {
229+
FATAL_ALL: 0,
230+
NO_FATAL: 1
231+
}
232+
233+
TransportManager.FaultTolerance = FAULT_TOLERANCE
234+
215235
module.exports = TransportManager

test/transports/transport-manager.spec.js

+54
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const mockUpgrader = require('../utils/mockUpgrader')
1515
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
1616
const { codes: ErrorCodes } = require('../../src/errors')
1717
const Libp2p = require('../../src')
18+
const { FaultTolerance } = require('../../src/transport-manager')
19+
1820
const Peers = require('../fixtures/peers')
1921
const PeerId = require('peer-id')
2022

@@ -165,3 +167,55 @@ describe('libp2p.transportManager', () => {
165167
expect(libp2p.transportManager.close.callCount).to.equal(1)
166168
})
167169
})
170+
171+
describe('libp2p.transportManager (dial only)', () => {
172+
let peerId
173+
let libp2p
174+
175+
before(async () => {
176+
peerId = await PeerId.createFromJSON(Peers[0])
177+
})
178+
179+
afterEach(async () => {
180+
sinon.restore()
181+
libp2p && await libp2p.stop()
182+
})
183+
184+
it('fails to start if multiaddr fails to listen', async () => {
185+
libp2p = new Libp2p({
186+
peerId,
187+
addresses: {
188+
listen: [multiaddr('/ip4/127.0.0.1/tcp/0')]
189+
},
190+
modules: {
191+
transport: [Transport]
192+
}
193+
})
194+
195+
try {
196+
await libp2p.start()
197+
} catch (err) {
198+
expect(err).to.exist()
199+
expect(err.code).to.equal(ErrorCodes.ERR_NO_VALID_ADDRESSES)
200+
return
201+
}
202+
throw new Error('it should fail to start if multiaddr fails to listen')
203+
})
204+
205+
it('does not fail to start if multiaddr fails to listen when supporting dial only mode', async () => {
206+
libp2p = new Libp2p({
207+
peerId,
208+
addresses: {
209+
listen: [multiaddr('/ip4/127.0.0.1/tcp/0')]
210+
},
211+
transportManager: {
212+
faultTolerance: FaultTolerance.NO_FATAL
213+
},
214+
modules: {
215+
transport: [Transport]
216+
}
217+
})
218+
219+
await libp2p.start()
220+
})
221+
})

0 commit comments

Comments
 (0)