Skip to content

Commit

Permalink
Tor improvements and better test fix
Browse files Browse the repository at this point in the history
  • Loading branch information
ikoenigsknecht committed May 23, 2024
1 parent 97719b2 commit c745690
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,19 @@ describe('Connections manager', () => {
hiddenService: userIdentity.hiddenService,
},
}
const emitSpy = jest.spyOn(libp2pService, 'emit')
await connectionsManagerService.init()
await connectionsManagerService.launchCommunity(launchCommunityPayload)
await sleep(5000)
await waitForExpect(async () => {
expect(emitSpy).toHaveBeenCalledWith(Libp2pEvents.INITIAL_DIAL)
}, 30000)

// It looks LibP2P dials peers initially when it's started and
// then IPFS service dials peers again when started, thus
// peersCount-1 * 2 because we don't dial ourself (the first peer in the list)
expect(spyOnDial).toHaveBeenCalledTimes((peersCount - 1) * 2)
await waitForExpect(async () => {
expect(spyOnDial).toHaveBeenCalledTimes((peersCount - 1) * 2)
}, 45000)
// Temporary fix for hanging test - websocketOverTor doesn't have abortController
await sleep(5000)
})
Expand Down
14 changes: 10 additions & 4 deletions packages/backend/src/nest/ipfs/ipfs.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Inject, Injectable } from '@nestjs/common'
import { LazyModuleLoader } from '@nestjs/core'
import { create, IPFS } from 'ipfs-core'
import { create, IPFS, Options as IPFSOptions } from 'ipfs-core'
import { IPFS_REPO_PATCH } from '../const'
import Logger from '../common/logger'
import { Libp2p } from 'libp2p'

@Injectable()
export class IpfsService {
Expand All @@ -29,9 +30,12 @@ export class IpfsService {
this.logger.error('no libp2p instance')
throw new Error('no libp2p instance')
}
ipfs = await create({
const getLibp2p = async (...args: any[]): Promise<Libp2p> => {
return libp2pInstance
}
const ipfsConfig: IPFSOptions = {
start: false,
libp2p: async () => libp2pInstance,
libp2p: getLibp2p,
preload: { enabled: false },
repo: this.ipfsRepoPath,
EXPERIMENTAL: {
Expand All @@ -40,7 +44,9 @@ export class IpfsService {
init: {
privateKey: peerId,
},
})
}
this.logger('Creating new ipfs instance')
ipfs = await create(ipfsConfig)
this.ipfsInstance = ipfs
} catch (error) {
this.logger.error('ipfs creation failed', error)
Expand Down
24 changes: 20 additions & 4 deletions packages/backend/src/nest/libp2p/libp2p.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import crypto from 'crypto'
import { EventEmitter } from 'events'
import { Agent } from 'https'
import { createServer } from 'it-ws'
import { Libp2p, createLibp2p } from 'libp2p'
import { Libp2p, createLibp2p, Libp2pOptions } from 'libp2p'
import { preSharedKey } from 'libp2p/pnet'
import { DateTime } from 'luxon'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
Expand Down Expand Up @@ -163,21 +163,26 @@ export class Libp2pService extends EventEmitter {
}

public async createInstance(params: Libp2pNodeParams, startDialImmediately: boolean = false): Promise<Libp2p> {
this.logger(`Creating new libp2p instance`)
if (this.libp2pInstance) {
this.logger(`Libp2p instance already exists`)
return this.libp2pInstance
}

let libp2p: Libp2p
const maxParallelDials = 2

try {
libp2p = await createLibp2p({
const libp2pConfig: Libp2pOptions = {
start: false,
connectionManager: {
minConnections: 5, // TODO: increase?
maxConnections: 20, // TODO: increase?
dialTimeout: 120000,
dialTimeout: 90_000,
maxParallelDials,
maxIncomingPendingConnections: 30,
inboundConnectionThreshold: 30,
inboundUpgradeTimeout: 45_000,
autoDial: true, // It's a default but let's set it to have explicit information
},
peerId: params.peerId,
Expand All @@ -196,6 +201,16 @@ export class Libp2pService extends EventEmitter {
active: false,
},
},
// ping: {
// maxInboundStreams: 10,
// maxOutboundStreams: 10,
// timeout: 15_000
// },
// fetch: {
// maxInboundStreams: 10,
// maxOutboundStreams: 10,
// timeout: 15_000
// },
transports: [
webSockets({
filter: all,
Expand All @@ -212,7 +227,8 @@ export class Libp2pService extends EventEmitter {
allowPublishToZeroPeers: true,
doPX: true,
}),
})
}
libp2p = await createLibp2p(libp2pConfig)
} catch (err) {
this.logger.error('Create libp2p:', err)
throw err
Expand Down
20 changes: 16 additions & 4 deletions packages/backend/src/nest/tor/tor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,22 @@ export class Tor extends EventEmitter implements OnModuleInit {
this.controlPort = port
}

mergeDefaultTorParams = (params: TorParams = {}): TorParams => {
const defaultParams = {
private mergeDefaultTorParams(params: TorParams = {}): TorParams {
const defaultParams: TorParams = {
'--NumEntryGuards': '3', // See task #1295
'--LearnCircuitBuildTimeout': '1',
'--CircuitBuildTimeout': '10',
'--KeepalivePeriod': '15',
'--NewCircuitPeriod': '300',
}
return { ...defaultParams, ...params }
}

private mergeDefaultTorParamsAndFlatten(params: TorParams = {}): string[] {
const mergedParams = this.mergeDefaultTorParams(params)
return Array.from(Object.entries(mergedParams)).flat()
}

get torProcessParams(): string[] {
return Array.from(Object.entries(this.extraTorProcessParams)).flat()
}
Expand Down Expand Up @@ -134,11 +143,12 @@ export class Tor extends EventEmitter implements OnModuleInit {
this.logger(`Sending ${SocketActionTypes.INITIAL_DIAL}`)
this.emit(SocketActionTypes.INITIAL_DIAL)
clearInterval(this.interval)
resolve()
clearTimeout(this.initTimeout)
}
}, 2500)

this.logger(`Spawned tor with pid(s): ${this.getTorProcessIds()}`)
resolve()
} catch (e) {
this.logger('Killing tor due to error', e)
this.clearHangingTorProcess()
Expand Down Expand Up @@ -267,7 +277,9 @@ export class Tor extends EventEmitter implements OnModuleInit {
`"${this.torDataDirectory}"`,
'--HashedControlPassword',
this.torPasswordProvider.torHashedPassword,
// ...this.torProcessParams
'--LongLivedPorts',
`80,${this.configOptions.httpTunnelPort},${this.socksPort}`,
...this.mergeDefaultTorParamsAndFlatten(),
],
options
)
Expand Down
6 changes: 6 additions & 0 deletions packages/mobile/ios/TorHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ class TorHandler: NSObject {
"--ControlPort", "127.0.0.1:\(controlPort)",
"--HTTPTunnelPort", "127.0.0.1:\(httpTunnelPort)",
"--Log", log_loc,
"--NumEntryGuards", "3",
"--LearnCircuitBuildTimeout", "1",
"--CircuitBuildTimeout", "10",
"--KeepalivePeriod", "15",
"--NewCircuitPeriod", "300",
"--LongLivedPorts", "80,\(socksPort),\(httpTunnelPort)",
]

if let dataDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
Expand Down

0 comments on commit c745690

Please sign in to comment.