Skip to content

Commit

Permalink
fix: Handle non-integers passed as connection limits (libp2p#1571)
Browse files Browse the repository at this point in the history
  • Loading branch information
maschad committed Jan 30, 2023
1 parent 4084163 commit 4e01ede
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/connection-manager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven

this.opts = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, init)

if (this.opts.minConnections < 0) {
throw errCode(new Error('Connection Manager minConnections must be greater than 0'), codes.ERR_INVALID_PARAMETERS)
}

if (this.opts.maxConnections < 0) {
throw errCode(new Error('Connection Manager maxConnections must be greater than 0'), codes.ERR_INVALID_PARAMETERS)
}

this.opts.maxConnections = Math.trunc(this.opts.maxConnections)
this.opts.minConnections = Math.trunc(this.opts.minConnections)

if (this.opts.maxConnections < this.opts.minConnections) {
throw errCode(new Error('Connection Manager maxConnections must be greater than minConnections'), codes.ERR_INVALID_PARAMETERS)
}
Expand Down
31 changes: 31 additions & 0 deletions test/connection-manager/index.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,37 @@ describe('libp2p.connections', () => {
await libp2p.stop()
})

it('Should convert minConnections from float to int', async () => {
const minConnections = 1.2
libp2p = await createNode({
started: false,
config: {
addresses: {
listen: ['/ip4/127.0.0.1/tcp/0/ws']
},
connectionManager: {
minConnections,
maxConnections: 1
}
}
})

// Populate PeerStore before starting
await libp2p.peerStore.addressBook.set(nodes[0].peerId, nodes[0].getMultiaddrs())
await libp2p.peerStore.addressBook.set(nodes[1].peerId, nodes[1].getMultiaddrs())

await libp2p.start()

// Wait for peer to connect
await pWaitFor(() => libp2p.connectionManager.getConnections().length === minConnections)

// Wait more time to guarantee no other connection happened
await delay(200)
expect(libp2p.connectionManager.getConnections().length).to.eql(minConnections)

await libp2p.stop()
})

// flaky
it.skip('should connect to all the peers stored in the PeerStore until reaching the minConnections sorted', async () => {
const minConnections = 1
Expand Down
45 changes: 45 additions & 0 deletions test/connection-manager/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { Dialer } from '@libp2p/interface-connection-manager'
import type { Connection } from '@libp2p/interface-connection'
import type { Upgrader } from '@libp2p/interface-transport'
import type { PeerStore } from '@libp2p/interface-peer-store'
import { codes } from '../../src/errors.js'

const defaultOptions = {
maxConnections: 10,
Expand Down Expand Up @@ -198,6 +199,50 @@ describe('Connection Manager', () => {
expect(spy).to.have.property('callCount', 1)
})

it('should fail if the connection manager has negative maxConnections limit', async () => {
await expect(createNode({
config: createBaseOptions({
connectionManager: { maxConnections: -5 }
}),
started: false
})).to.eventually.rejected('maxConnections must be greater than 0').with.property('code', codes.ERR_INVALID_PARAMETERS)
})

it('should fail if the connection manager has negative minConnections limit', async () => {
await expect(createNode({
config: createBaseOptions({
connectionManager: { minConnections: -5 }
}),
started: false
})).to.eventually.rejected('minConnections must be greater than 0').with.property('code', codes.ERR_INVALID_PARAMETERS)
})

it('Should convert maxConnections from float to int', async () => {
const max = 3.2
libp2p = await createNode({
config: createBaseOptions({
connectionManager: {
maxConnections: max,
minConnections: 1
}
}),
started: false
})

await libp2p.start()

const connectionManager = libp2p.connectionManager as DefaultConnectionManager
const connectionManagerMaybeDisconnectOneSpy = sinon.spy(connectionManager, '_pruneConnections')

for (let i = 0; i < Math.trunc(max) + 1; i++) {
const connection = mockConnection(mockMultiaddrConnection(mockDuplex(), await createEd25519PeerId()))

await connectionManager._onConnect(new CustomEvent('connection', { detail: connection }))
}

expect(connectionManagerMaybeDisconnectOneSpy.callCount).to.equal(1)
})

it('should fail if the connection manager has mismatched connection limit options', async () => {
await expect(createNode({
config: createBaseOptions({
Expand Down

0 comments on commit 4e01ede

Please sign in to comment.