From 0f394b3a2af8ea39e3796407290c9e4d1a302cc9 Mon Sep 17 00:00:00 2001 From: Chad Nehemiah Date: Thu, 5 Oct 2023 18:34:21 -0500 Subject: [PATCH 01/15] feat: configuration validation (#1778) Co-authored-by: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> --- packages/libp2p/.aegir.js | 6 +- packages/libp2p/package.json | 3 +- packages/libp2p/src/address-manager/utils.ts | 14 ++++ packages/libp2p/src/autonat/index.ts | 22 ++++-- .../libp2p/src/circuit-relay/constants.ts | 5 ++ .../libp2p/src/circuit-relay/server/index.ts | 32 ++++++-- .../circuit-relay/server/reservation-store.ts | 22 ++++-- .../src/circuit-relay/transport/index.ts | 30 ++++---- packages/libp2p/src/config.ts | 41 ---------- packages/libp2p/src/config/config.ts | 44 +++++++++++ packages/libp2p/src/config/helpers.ts | 12 +++ .../libp2p/src/connection-manager/utils.ts | 23 ++++++ packages/libp2p/src/dcutr/dcutr.ts | 27 +++---- packages/libp2p/src/fetch/constants.ts | 4 + packages/libp2p/src/fetch/index.ts | 31 +++++--- packages/libp2p/src/identify/consts.ts | 13 ++++ packages/libp2p/src/identify/identify.ts | 75 +++++++++++-------- packages/libp2p/src/identify/index.ts | 5 +- packages/libp2p/src/libp2p.ts | 2 +- packages/libp2p/src/ping/index.ts | 20 +++-- packages/libp2p/src/upnp-nat/index.ts | 28 +++++-- .../test/circuit-relay/discovery.node.ts | 2 + .../configuration/protocol-prefix.node.ts | 3 +- .../test/connection-manager/index.node.ts | 4 +- .../test/connection-manager/index.spec.ts | 20 +++-- .../test/connection-manager/resolver.spec.ts | 4 +- packages/libp2p/test/ping/ping.node.ts | 5 ++ packages/transport-webrtc/.aegir.js | 3 +- 28 files changed, 338 insertions(+), 162 deletions(-) delete mode 100644 packages/libp2p/src/config.ts create mode 100644 packages/libp2p/src/config/config.ts create mode 100644 packages/libp2p/src/config/helpers.ts diff --git a/packages/libp2p/.aegir.js b/packages/libp2p/.aegir.js index a0d8cbc706..36fea1dd21 100644 --- a/packages/libp2p/.aegir.js +++ b/packages/libp2p/.aegir.js @@ -24,7 +24,9 @@ export default { const peerId = await createEd25519PeerId() const libp2p = await createLibp2p({ connectionManager: { - inboundConnectionThreshold: Infinity, + inboundConnectionThreshold: 1000, + maxIncomingPendingConnections: 1000, + maxConnections: 1000, minConnections: 0 }, addresses: { @@ -51,7 +53,7 @@ export default { fetch: fetchService(), relay: circuitRelayServer({ reservations: { - maxReservations: Infinity + maxReservations: 100000 } }) } diff --git a/packages/libp2p/package.json b/packages/libp2p/package.json index 10b4827403..3b5b1879da 100644 --- a/packages/libp2p/package.json +++ b/packages/libp2p/package.json @@ -164,7 +164,8 @@ "uint8arraylist": "^2.4.3", "uint8arrays": "^4.0.6", "wherearewe": "^2.0.1", - "xsalsa20": "^1.1.0" + "xsalsa20": "^1.1.0", + "yup": "^1.2.0" }, "devDependencies": { "@chainsafe/libp2p-gossipsub": "^10.0.0", diff --git a/packages/libp2p/src/address-manager/utils.ts b/packages/libp2p/src/address-manager/utils.ts index 7062446a86..c0b53ec010 100644 --- a/packages/libp2p/src/address-manager/utils.ts +++ b/packages/libp2p/src/address-manager/utils.ts @@ -1,3 +1,8 @@ +import { type ObjectSchema, object, array, string, mixed } from 'yup' +import { validateMultiaddr } from '../config/helpers.js' +import type { AddressManagerInit } from '.' +import type { Multiaddr } from '@multiformats/multiaddr' + export function debounce (func: () => void, wait: number): () => void { let timeout: ReturnType | undefined @@ -11,3 +16,12 @@ export function debounce (func: () => void, wait: number): () => void { timeout = setTimeout(later, wait) } } + +export function validateAddressManagerConfig (opts: AddressManagerInit): ObjectSchema> { + return object({ + listen: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), + announce: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), + noAnnounce: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), + announceFilter: mixed().default(() => (addrs: Multiaddr[]): Multiaddr[] => addrs) + }) +} diff --git a/packages/libp2p/src/autonat/index.ts b/packages/libp2p/src/autonat/index.ts index 3f70e6a850..319493d39b 100644 --- a/packages/libp2p/src/autonat/index.ts +++ b/packages/libp2p/src/autonat/index.ts @@ -31,6 +31,7 @@ import map from 'it-map' import parallel from 'it-parallel' import { pipe } from 'it-pipe' import isPrivateIp from 'private-ip' +import { number, object, string } from 'yup' import { codes } from '../errors.js' import { MAX_INBOUND_STREAMS, @@ -108,14 +109,23 @@ class DefaultAutoNATService implements Startable { private started: boolean constructor (components: AutoNATComponents, init: AutoNATServiceInit) { + const validatedConfig = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + timeout: number().integer().default(TIMEOUT), + startupDelay: number().integer().default(STARTUP_DELAY), + refreshInterval: number().integer().default(REFRESH_INTERVAL), + maxInboundStreams: number().integer().default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().default(MAX_OUTBOUND_STREAMS) + }).validateSync(init) + this.components = components this.started = false - this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = init.timeout ?? TIMEOUT - this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS - this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS - this.startupDelay = init.startupDelay ?? STARTUP_DELAY - this.refreshInterval = init.refreshInterval ?? REFRESH_INTERVAL + this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = validatedConfig.timeout + this.maxInboundStreams = validatedConfig.maxInboundStreams + this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.startupDelay = validatedConfig.startupDelay + this.refreshInterval = validatedConfig.refreshInterval this._verifyExternalAddresses = this._verifyExternalAddresses.bind(this) } diff --git a/packages/libp2p/src/circuit-relay/constants.ts b/packages/libp2p/src/circuit-relay/constants.ts index d35f45881a..7907ed5817 100644 --- a/packages/libp2p/src/circuit-relay/constants.ts +++ b/packages/libp2p/src/circuit-relay/constants.ts @@ -70,3 +70,8 @@ export const DEFAULT_HOP_TIMEOUT = 30 * second * How long to wait before starting to advertise the relay service */ export const DEFAULT_ADVERT_BOOT_DELAY = 30 * second + +/** + * The default timeout for Incoming STOP requests from the relay + */ +export const DEFAULT_STOP_TIMEOUT = 30 * second diff --git a/packages/libp2p/src/circuit-relay/server/index.ts b/packages/libp2p/src/circuit-relay/server/index.ts index aed3d5be8b..758db09e4d 100644 --- a/packages/libp2p/src/circuit-relay/server/index.ts +++ b/packages/libp2p/src/circuit-relay/server/index.ts @@ -6,10 +6,16 @@ import { RecordEnvelope } from '@libp2p/peer-record' import { type Multiaddr, multiaddr } from '@multiformats/multiaddr' import { pbStream, type ProtobufStream } from 'it-protobuf-stream' import pDefer from 'p-defer' +import { object, number, boolean } from 'yup' import { MAX_CONNECTIONS } from '../../connection-manager/constants.js' +import { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from '../../registrar.js' import { CIRCUIT_PROTO_CODE, + DEFAULT_DURATION_LIMIT, DEFAULT_HOP_TIMEOUT, + DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, + DEFAULT_MAX_RESERVATION_STORE_SIZE, + DEFAULT_MAX_RESERVATION_TTL, RELAY_SOURCE_TAG, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC @@ -95,10 +101,6 @@ export interface RelayServerEvents { 'relay:advert:error': CustomEvent } -const defaults = { - maxOutboundStopStreams: MAX_CONNECTIONS -} - class CircuitRelayServer extends EventEmitter implements Startable, CircuitRelayService { private readonly registrar: Registrar private readonly peerStore: PeerStore @@ -121,6 +123,20 @@ class CircuitRelayServer extends EventEmitter implements Star constructor (components: CircuitRelayServerComponents, init: CircuitRelayServerInit = {}) { super() + const validatedConfig = object({ + hopTimeout: number().min(0).integer().default(DEFAULT_HOP_TIMEOUT), + reservations: object({ + maxReservations: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_STORE_SIZE), + reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), + applyDefaultLimit: boolean().default(true), + reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), + defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT).max(init?.reservations?.reservationTtl ?? DEFAULT_MAX_RESERVATION_TTL, `default duration limit must be less than reservation TTL: ${init?.reservations?.reservationTtl}`) + }), + maxInboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_INBOUND_STREAMS), + maxOutboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_OUTBOUND_STREAMS), + maxOutboundStopStreams: number().integer().min(0).default(MAX_CONNECTIONS) + }).validateSync(init) + this.registrar = components.registrar this.peerStore = components.peerStore this.addressManager = components.addressManager @@ -128,11 +144,11 @@ class CircuitRelayServer extends EventEmitter implements Star this.connectionManager = components.connectionManager this.connectionGater = components.connectionGater this.started = false - this.hopTimeout = init?.hopTimeout ?? DEFAULT_HOP_TIMEOUT + this.hopTimeout = validatedConfig.hopTimeout this.shutdownController = new AbortController() - this.maxInboundHopStreams = init.maxInboundHopStreams - this.maxOutboundHopStreams = init.maxOutboundHopStreams - this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams + this.maxInboundHopStreams = validatedConfig.maxInboundHopStreams + this.maxOutboundHopStreams = validatedConfig.maxOutboundHopStreams + this.maxOutboundStopStreams = validatedConfig.maxOutboundStopStreams try { // fails on node < 15.4 diff --git a/packages/libp2p/src/circuit-relay/server/reservation-store.ts b/packages/libp2p/src/circuit-relay/server/reservation-store.ts index 0f5d3bf62e..36a747c99c 100644 --- a/packages/libp2p/src/circuit-relay/server/reservation-store.ts +++ b/packages/libp2p/src/circuit-relay/server/reservation-store.ts @@ -1,4 +1,5 @@ import { PeerMap } from '@libp2p/peer-collections' +import { object, mixed, number, boolean } from 'yup' import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js' import { type Limit, Status } from '../pb/index.js' import type { RelayReservation } from '../index.js' @@ -50,12 +51,21 @@ export class ReservationStore implements Startable { private readonly defaultDataLimit: bigint constructor (options: ReservationStoreOptions = {}) { - this.maxReservations = options.maxReservations ?? DEFAULT_MAX_RESERVATION_STORE_SIZE - this.reservationClearInterval = options.reservationClearInterval ?? DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL - this.applyDefaultLimit = options.applyDefaultLimit !== false - this.reservationTtl = options.reservationTtl ?? DEFAULT_MAX_RESERVATION_TTL - this.defaultDurationLimit = options.defaultDurationLimit ?? DEFAULT_DURATION_LIMIT - this.defaultDataLimit = options.defaultDataLimit ?? DEFAULT_DATA_LIMIT + const validatedConfig = object({ + maxReservations: number().min(0).integer().default(DEFAULT_MAX_RESERVATION_STORE_SIZE), + reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), + applyDefaultLimit: boolean().default(true), + reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), + defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT), + defaultDataLimit: mixed().test('is-bigint', 'Invalid bigint', value => typeof value === 'bigint').default(DEFAULT_DATA_LIMIT) + }).validateSync(options) + + this.maxReservations = validatedConfig.maxReservations + this.reservationClearInterval = validatedConfig.reservationClearInterval + this.applyDefaultLimit = validatedConfig.applyDefaultLimit + this.reservationTtl = validatedConfig.reservationTtl + this.defaultDurationLimit = validatedConfig.defaultDurationLimit + this.defaultDataLimit = validatedConfig.defaultDataLimit as bigint } isStarted (): boolean { diff --git a/packages/libp2p/src/circuit-relay/transport/index.ts b/packages/libp2p/src/circuit-relay/transport/index.ts index 483f9a0366..6125c55b20 100644 --- a/packages/libp2p/src/circuit-relay/transport/index.ts +++ b/packages/libp2p/src/circuit-relay/transport/index.ts @@ -6,9 +6,10 @@ import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn' import * as mafmt from '@multiformats/mafmt' import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' +import { number, object } from 'yup' import { MAX_CONNECTIONS } from '../../connection-manager/constants.js' import { codes } from '../../errors.js' -import { CIRCUIT_PROTO_CODE, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' +import { CIRCUIT_PROTO_CODE, DEFAULT_STOP_TIMEOUT, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' import { StopMessage, HopMessage, Status } from '../pb/index.js' import { RelayDiscovery, type RelayDiscoveryComponents } from './discovery.js' import { createListener } from './listener.js' @@ -100,12 +101,6 @@ export interface CircuitRelayTransportInit extends RelayStoreInit { reservationCompletionTimeout?: number } -const defaults = { - maxInboundStopStreams: MAX_CONNECTIONS, - maxOutboundStopStreams: MAX_CONNECTIONS, - stopTimeout: 30000 -} - class CircuitRelayTransport implements Transport { private readonly discovery?: RelayDiscovery private readonly registrar: Registrar @@ -116,12 +111,19 @@ class CircuitRelayTransport implements Transport { private readonly addressManager: AddressManager private readonly connectionGater: ConnectionGater private readonly reservationStore: ReservationStore - private readonly maxInboundStopStreams: number + private readonly maxInboundStopStreams?: number private readonly maxOutboundStopStreams?: number - private readonly stopTimeout: number + private readonly stopTimeout?: number private started: boolean constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) { + const validatedConfig = object({ + discoverRelays: number().min(0).integer().default(0), + maxInboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + maxOutboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + stopTimeout: number().min(0).integer().default(DEFAULT_STOP_TIMEOUT) + }).validateSync(init) + this.registrar = components.registrar this.peerStore = components.peerStore this.connectionManager = components.connectionManager @@ -129,11 +131,11 @@ class CircuitRelayTransport implements Transport { this.upgrader = components.upgrader this.addressManager = components.addressManager this.connectionGater = components.connectionGater - this.maxInboundStopStreams = init.maxInboundStopStreams ?? defaults.maxInboundStopStreams - this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams - this.stopTimeout = init.stopTimeout ?? defaults.stopTimeout + this.maxInboundStopStreams = validatedConfig.maxInboundStopStreams + this.maxOutboundStopStreams = validatedConfig.maxOutboundStopStreams + this.stopTimeout = validatedConfig.stopTimeout - if (init.discoverRelays != null && init.discoverRelays > 0) { + if (validatedConfig.discoverRelays > 0) { this.discovery = new RelayDiscovery(components) this.discovery.addEventListener('relay:discover', (evt) => { this.reservationStore.addRelay(evt.detail, 'discovered') @@ -321,7 +323,7 @@ class CircuitRelayTransport implements Transport { * An incoming STOP request means a remote peer wants to dial us via a relay */ async onStop ({ connection, stream }: IncomingStreamData): Promise { - const signal = AbortSignal.timeout(this.stopTimeout) + const signal = AbortSignal.timeout(this.stopTimeout ?? DEFAULT_STOP_TIMEOUT) const pbstr = pbStream(stream).pb(StopMessage) const request = await pbstr.read({ signal diff --git a/packages/libp2p/src/config.ts b/packages/libp2p/src/config.ts deleted file mode 100644 index a9b83fb532..0000000000 --- a/packages/libp2p/src/config.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { CodeError } from '@libp2p/interface/errors' -import { FaultTolerance } from '@libp2p/interface/transport' -import { defaultAddressSort } from '@libp2p/utils/address-sort' -import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' -import mergeOptions from 'merge-options' -import { codes, messages } from './errors.js' -import type { Libp2pInit } from './index.js' -import type { ServiceMap, RecursivePartial } from '@libp2p/interface' -import type { Multiaddr } from '@multiformats/multiaddr' - -const DefaultConfig: Partial = { - addresses: { - listen: [], - announce: [], - noAnnounce: [], - announceFilter: (multiaddrs: Multiaddr[]) => multiaddrs - }, - connectionManager: { - resolvers: { - dnsaddr: dnsaddrResolver - }, - addressSorter: defaultAddressSort - }, - transportManager: { - faultTolerance: FaultTolerance.FATAL_ALL - } -} - -export function validateConfig > (opts: RecursivePartial>): Libp2pInit { - const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, opts) - - if (resultingOptions.transports == null || resultingOptions.transports.length < 1) { - throw new CodeError(messages.ERR_TRANSPORTS_REQUIRED, codes.ERR_TRANSPORTS_REQUIRED) - } - - if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) { // eslint-disable-line no-undef - throw new CodeError(messages.ERR_PROTECTOR_REQUIRED, codes.ERR_PROTECTOR_REQUIRED) - } - - return resultingOptions -} diff --git a/packages/libp2p/src/config/config.ts b/packages/libp2p/src/config/config.ts new file mode 100644 index 0000000000..fb928825eb --- /dev/null +++ b/packages/libp2p/src/config/config.ts @@ -0,0 +1,44 @@ +import { FaultTolerance } from '@libp2p/interface/transport' +import { publicAddressesFirst } from '@libp2p/utils/address-sort' +import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' +import mergeOptions from 'merge-options' +import { object } from 'yup' +import { validateAddressManagerConfig } from '../address-manager/utils.js' +import { validateConnectionManagerConfig } from '../connection-manager/utils.js' +import type { AddressManagerInit } from '../address-manager' +import type { ConnectionManagerInit } from '../connection-manager/index.js' +import type { Libp2pInit } from '../index.js' +import type { ServiceMap, RecursivePartial } from '@libp2p/interface' + +const DefaultConfig: Partial = { + connectionManager: { + resolvers: { + dnsaddr: dnsaddrResolver + }, + addressSorter: publicAddressesFirst + }, + transportManager: { + faultTolerance: FaultTolerance.FATAL_ALL + } +} + +export function validateConfig > (opts: RecursivePartial>): Libp2pInit { + const libp2pConfig = object({ + addresses: validateAddressManagerConfig(opts?.addresses as AddressManagerInit), + connectionManager: validateConnectionManagerConfig(opts?.connectionManager as ConnectionManagerInit) + }) + + if ((opts?.services) != null) { + // @ts-expect-error until we resolve https://github.com/libp2p/js-libp2p/pull/1762 and have a better way of discovering type dependencies + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + if ((opts.services?.kadDHT || opts.services?.relay || opts.services?.ping) && !opts.services.identify) { + throw new Error('identify service is required when using kadDHT, relay, or ping') + } + } + + const parsedOpts = libp2pConfig.validateSync(opts) + + const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, parsedOpts) + + return resultingOptions +} diff --git a/packages/libp2p/src/config/helpers.ts b/packages/libp2p/src/config/helpers.ts new file mode 100644 index 0000000000..9cb4106ae8 --- /dev/null +++ b/packages/libp2p/src/config/helpers.ts @@ -0,0 +1,12 @@ +import { multiaddr } from '@multiformats/multiaddr' + +export const validateMultiaddr = (value: Array | undefined): boolean => { + value?.forEach((addr) => { + try { + multiaddr(addr) + } catch (err) { + throw new Error(`invalid multiaddr: ${addr}`) + } + }) + return true +} diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index e195e48bf6..760461beab 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -2,6 +2,10 @@ import { setMaxListeners } from 'events' import { logger } from '@libp2p/logger' import { type AbortOptions, multiaddr, type Multiaddr } from '@multiformats/multiaddr' import { type ClearableSignal, anySignal } from 'any-signal' +import { type ObjectSchema, array, number, object, string } from 'yup' +import { validateMultiaddr } from '../config/helpers.js' +import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_INTERVAL, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, INBOUND_UPGRADE_TIMEOUT, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PARALLEL_DIALS_PER_PEER, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js' +import type { ConnectionManagerInit } from '.' const log = logger('libp2p:connection-manager:utils') @@ -73,3 +77,22 @@ export function combineSignals (...signals: Array): Cle return signal } + +export const validateConnectionManagerConfig = (opts: ConnectionManagerInit): ObjectSchema> => { + return object({ + maxConnections: number().min(opts?.minConnections ?? MIN_CONNECTIONS, `maxConnections must be greater than the min connections limit: ${opts?.minConnections}`).integer().default(MAX_CONNECTIONS), + minConnections: number().min(0).integer().max(opts?.maxConnections ?? MAX_CONNECTIONS, `minConnections must be less than the max connections limit: ${opts?.maxConnections}`).default(MIN_CONNECTIONS), + autoDialInterval: number().min(0).integer().default(AUTO_DIAL_INTERVAL), + autoDialConcurrency: number().min(0).integer().default(AUTO_DIAL_CONCURRENCY), + autoDialPriority: number().min(0).integer().default(AUTO_DIAL_PRIORITY), + maxParallelDials: number().min(0).integer().default(MAX_PARALLEL_DIALS), + maxParallelDialsPerPeer: number().max(opts?.autoDialConcurrency ?? AUTO_DIAL_CONCURRENCY, `maxParallelDialsPerPeer must be less than the min auto dial conccurency limit: ${opts?.autoDialConcurrency}`).default(MAX_PARALLEL_DIALS_PER_PEER), + maxPeerAddrsToDialed: number().min(0).integer().default(MAX_PEER_ADDRS_TO_DIAL), + dialTimeout: number().min(0).integer().default(DIAL_TIMEOUT), + inboundUpgradeTimeout: number().integer().default(INBOUND_UPGRADE_TIMEOUT), + allow: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), + deny: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), + inboundConnectionThreshold: number().max(opts?.maxConnections ?? MAX_CONNECTIONS, `inboundConnectionThreshold must be less than the max connections limit: ${opts?.inboundConnectionThreshold}`).integer().default(INBOUND_CONNECTION_THRESHOLD), + maxIncomingPendingConnections: number().integer().max(opts?.maxConnections ?? MAX_CONNECTIONS, `maxIncomingPendingConnections must be less than the max connections limit: ${opts?.maxIncomingPendingConnections}`).default(MAX_INCOMING_PENDING_CONNECTIONS) + }) +} diff --git a/packages/libp2p/src/dcutr/dcutr.ts b/packages/libp2p/src/dcutr/dcutr.ts index 190766bfa2..6639a356f1 100644 --- a/packages/libp2p/src/dcutr/dcutr.ts +++ b/packages/libp2p/src/dcutr/dcutr.ts @@ -5,6 +5,7 @@ import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher' import delay from 'delay' import { pbStream } from 'it-protobuf-stream' import isPrivate from 'private-ip' +import { number, object } from 'yup' import { codes } from '../errors.js' import { HolePunch } from './pb/message.js' import { multicodec } from './index.js' @@ -24,15 +25,6 @@ const MAX_DCUTR_MESSAGE_SIZE = 1024 * 4 // ensure the dial has a high priority to jump to the head of the dial queue const DCUTR_DIAL_PRIORITY = 100 -const defaultValues = { - // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 - timeout: 5000, - // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 - retries: 3, - maxInboundStreams: 1, - maxOutboundStreams: 1 -} - export class DefaultDCUtRService implements Startable { private started: boolean private readonly timeout: number @@ -54,10 +46,19 @@ export class DefaultDCUtRService implements Startable { this.connectionManager = components.connectionManager this.transportManager = components.transportManager - this.timeout = init.timeout ?? defaultValues.timeout - this.retries = init.retries ?? defaultValues.retries - this.maxInboundStreams = init.maxInboundStreams ?? defaultValues.maxInboundStreams - this.maxOutboundStreams = init.maxOutboundStreams ?? defaultValues.maxOutboundStreams + const validatedConfig = object({ + // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 + timeout: number().integer().default(5000).min(1), + // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 + retries: number().integer().default(3).min(1), + maxInboundStreams: number().integer().default(1).min(1), + maxOutboundStreams: number().integer().default(1).min(1) + }).validateSync(init) + + this.timeout = validatedConfig.timeout + this.retries = validatedConfig.retries + this.maxInboundStreams = validatedConfig.maxInboundStreams + this.maxOutboundStreams = validatedConfig.maxOutboundStreams } isStarted (): boolean { diff --git a/packages/libp2p/src/fetch/constants.ts b/packages/libp2p/src/fetch/constants.ts index cbab081bcd..d0be9327b2 100644 --- a/packages/libp2p/src/fetch/constants.ts +++ b/packages/libp2p/src/fetch/constants.ts @@ -1,3 +1,7 @@ // https://github.com/libp2p/specs/tree/master/fetch#wire-protocol export const PROTOCOL_VERSION = '0.0.1' export const PROTOCOL_NAME = 'fetch' + +export const MAX_INBOUND_STREAMS = 1 +export const MAX_OUTBOUND_STREAMS = 1 +export const TIMEOUT = 60000 diff --git a/packages/libp2p/src/fetch/index.ts b/packages/libp2p/src/fetch/index.ts index 604fb15f3b..378919526b 100644 --- a/packages/libp2p/src/fetch/index.ts +++ b/packages/libp2p/src/fetch/index.ts @@ -6,8 +6,9 @@ import * as lp from 'it-length-prefixed' import { pipe } from 'it-pipe' import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' import { toString as uint8arrayToString } from 'uint8arrays/to-string' +import { number, object, string } from 'yup' import { codes } from '../errors.js' -import { PROTOCOL_NAME, PROTOCOL_VERSION } from './constants.js' +import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, PROTOCOL_VERSION, TIMEOUT } from './constants.js' import { FetchRequest, FetchResponse } from './pb/proto.js' import type { AbortOptions } from '@libp2p/interface' import type { Stream } from '@libp2p/interface/connection' @@ -18,8 +19,6 @@ import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/r const log = logger('libp2p:fetch') -const DEFAULT_TIMEOUT = 10000 - export interface FetchServiceInit { protocolPrefix?: string maxInboundStreams?: number @@ -94,15 +93,27 @@ class DefaultFetchService implements Startable, FetchService { private readonly components: FetchServiceComponents private readonly lookupFunctions: Map private started: boolean - private readonly init: FetchServiceInit + private readonly timeout: number + private readonly maxInboundStreams: number + private readonly maxOutboundStreams: number constructor (components: FetchServiceComponents, init: FetchServiceInit) { + const validatedConfig = object({ + protocolPrefix: string().default('libp2p'), + timeout: number().integer().default(TIMEOUT), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) + }).validateSync(init) + this.started = false this.components = components - this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = validatedConfig.timeout + this.maxInboundStreams = validatedConfig.maxInboundStreams + this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.lookupFunctions = new Map() // Maps key prefix to value lookup function this.handleMessage = this.handleMessage.bind(this) - this.init = init } async start (): Promise { @@ -115,8 +126,8 @@ class DefaultFetchService implements Startable, FetchService { log.error(err) }) }, { - maxInboundStreams: this.init.maxInboundStreams, - maxOutboundStreams: this.init.maxOutboundStreams + maxInboundStreams: this.maxInboundStreams, + maxOutboundStreams: this.maxOutboundStreams }) this.started = true } @@ -143,8 +154,8 @@ class DefaultFetchService implements Startable, FetchService { // create a timeout if no abort signal passed if (signal == null) { - log('using default timeout of %d ms', this.init.timeout) - signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT) + log('using default timeout of %d ms', this.timeout) + signal = AbortSignal.timeout(this.timeout) try { // fails on node < 15.4 diff --git a/packages/libp2p/src/identify/consts.ts b/packages/libp2p/src/identify/consts.ts index e65f222951..ae3356018e 100644 --- a/packages/libp2p/src/identify/consts.ts +++ b/packages/libp2p/src/identify/consts.ts @@ -5,8 +5,21 @@ export const AGENT_VERSION = `js-libp2p/${version}` export const MULTICODEC_IDENTIFY = '/ipfs/id/1.0.0' // deprecated export const MULTICODEC_IDENTIFY_PUSH = '/ipfs/id/push/1.0.0' // deprecated +export const PROTOCOL_PREFIX = 'ipfs' +export const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8 // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52 +export const MAX_INBOUND_STREAMS = 1 +export const MAX_OUTBOUND_STREAMS = 1 +export const MAX_PUSH_INCOMING_STREAMS = 1 +export const MAX_PUSH_OUTGOING_STREAMS = 1 +export const MAX_OBSERVED_ADDRESSES = 10 + +export const RUN_ON_TRANSIENT_CONNECTION = true +export const RUN_ON_CONNECTION_OPEN = true + export const IDENTIFY_PROTOCOL_VERSION = '0.1.0' export const MULTICODEC_IDENTIFY_PROTOCOL_NAME = 'id' export const MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME = 'id/push' export const MULTICODEC_IDENTIFY_PROTOCOL_VERSION = '1.0.0' export const MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION = '1.0.0' + +export const TIMEOUT = 60000 diff --git a/packages/libp2p/src/identify/identify.ts b/packages/libp2p/src/identify/identify.ts index caa5248b45..3e992da045 100644 --- a/packages/libp2p/src/identify/identify.ts +++ b/packages/libp2p/src/identify/identify.ts @@ -8,6 +8,7 @@ import { pbStream } from 'it-protobuf-stream' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe' +import { boolean, number, object, string } from 'yup' import { codes } from '../errors.js' import { AGENT_VERSION, @@ -15,7 +16,17 @@ import { MULTICODEC_IDENTIFY_PROTOCOL_NAME, MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME, MULTICODEC_IDENTIFY_PROTOCOL_VERSION, - MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION + MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION, + MAX_INBOUND_STREAMS, + MAX_OUTBOUND_STREAMS, + MAX_IDENTIFY_MESSAGE_SIZE, + TIMEOUT, + RUN_ON_CONNECTION_OPEN, + PROTOCOL_PREFIX, + RUN_ON_TRANSIENT_CONNECTION, + MAX_PUSH_INCOMING_STREAMS, + MAX_PUSH_OUTGOING_STREAMS, + MAX_OBSERVED_ADDRESSES } from './consts.js' import { Identify } from './pb/message.js' import type { IdentifyService, IdentifyServiceComponents, IdentifyServiceInit } from './index.js' @@ -31,24 +42,6 @@ import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/r const log = logger('libp2p:identify') -// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52 -const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8 - -const defaultValues = { - protocolPrefix: 'ipfs', - agentVersion: AGENT_VERSION, - // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48 - timeout: 60000, - maxInboundStreams: 1, - maxOutboundStreams: 1, - maxPushIncomingStreams: 1, - maxPushOutgoingStreams: 1, - maxObservedAddresses: 10, - maxIdentifyMessageSize: 8192, - runOnConnectionOpen: true, - runOnTransientConnection: true -} - export class DefaultIdentifyService implements Startable, IdentifyService { private readonly identifyProtocolStr: string private readonly identifyPushProtocolStr: string @@ -72,8 +65,23 @@ export class DefaultIdentifyService implements Startable, IdentifyService { private readonly maxObservedAddresses: number private readonly events: EventEmitter private readonly runOnTransientConnection: boolean + private readonly runOnConnectionOpen: boolean constructor (components: IdentifyServiceComponents, init: IdentifyServiceInit) { + const validatedConfig = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + agentVersion: string().default(AGENT_VERSION), + timeout: number().integer().default(TIMEOUT), + maxIdentifyMessageSize: number().integer().min(0).default(MAX_IDENTIFY_MESSAGE_SIZE), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxPushIncomingStreams: number().integer().min(0).default(MAX_PUSH_INCOMING_STREAMS), + maxPushOutgoingStreams: number().integer().min(0).default(MAX_PUSH_OUTGOING_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + maxObservedAddresses: number().integer().min(0).default(MAX_OBSERVED_ADDRESSES), + runOnConnectionOpen: boolean().default(RUN_ON_CONNECTION_OPEN), + runOnTransientConnection: boolean().default(RUN_ON_TRANSIENT_CONNECTION) + }).validateSync(init) + this.started = false this.peerId = components.peerId this.peerStore = components.peerStore @@ -82,24 +90,25 @@ export class DefaultIdentifyService implements Startable, IdentifyService { this.connectionManager = components.connectionManager this.events = components.events - this.identifyProtocolStr = `/${init.protocolPrefix ?? defaultValues.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}` - this.identifyPushProtocolStr = `/${init.protocolPrefix ?? defaultValues.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}` - this.timeout = init.timeout ?? defaultValues.timeout - this.maxInboundStreams = init.maxInboundStreams ?? defaultValues.maxInboundStreams - this.maxOutboundStreams = init.maxOutboundStreams ?? defaultValues.maxOutboundStreams - this.maxPushIncomingStreams = init.maxPushIncomingStreams ?? defaultValues.maxPushIncomingStreams - this.maxPushOutgoingStreams = init.maxPushOutgoingStreams ?? defaultValues.maxPushOutgoingStreams - this.maxIdentifyMessageSize = init.maxIdentifyMessageSize ?? defaultValues.maxIdentifyMessageSize - this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses - this.runOnTransientConnection = init.runOnTransientConnection ?? defaultValues.runOnTransientConnection + this.identifyProtocolStr = `/${validatedConfig.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}` + this.identifyPushProtocolStr = `/${validatedConfig.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}` + this.timeout = validatedConfig.timeout + this.maxInboundStreams = validatedConfig.maxInboundStreams + this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.maxPushIncomingStreams = validatedConfig.maxPushIncomingStreams + this.maxPushOutgoingStreams = validatedConfig.maxPushOutgoingStreams + this.maxIdentifyMessageSize = validatedConfig.maxIdentifyMessageSize + this.maxObservedAddresses = validatedConfig.maxObservedAddresses + this.runOnTransientConnection = validatedConfig.runOnTransientConnection + this.runOnConnectionOpen = validatedConfig.runOnConnectionOpen // Store self host metadata this.host = { - protocolVersion: `${init.protocolPrefix ?? defaultValues.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`, - agentVersion: init.agentVersion ?? defaultValues.agentVersion + protocolVersion: `${validatedConfig.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`, + agentVersion: validatedConfig.agentVersion } - if (init.runOnConnectionOpen ?? defaultValues.runOnConnectionOpen) { + if (this.runOnConnectionOpen) { // When a new connection happens, trigger identify components.events.addEventListener('connection:open', (evt) => { const connection = evt.detail @@ -313,7 +322,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { log('our observed address is %a', cleanObservedAddr) if (cleanObservedAddr != null && - this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses ?? Infinity)) { + this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses)) { log('storing our observed address %a', cleanObservedAddr) this.addressManager.addObservedAddr(cleanObservedAddr) } diff --git a/packages/libp2p/src/identify/index.ts b/packages/libp2p/src/identify/index.ts index a61309b3d3..cd8e6a7ab4 100644 --- a/packages/libp2p/src/identify/index.ts +++ b/packages/libp2p/src/identify/index.ts @@ -1,7 +1,4 @@ -import { - MULTICODEC_IDENTIFY, - MULTICODEC_IDENTIFY_PUSH -} from './consts.js' +import { MULTICODEC_IDENTIFY, MULTICODEC_IDENTIFY_PUSH } from './consts.js' import { DefaultIdentifyService } from './identify.js' import { Identify } from './pb/message.js' import type { AbortOptions, IdentifyResult, Libp2pEvents } from '@libp2p/interface' diff --git a/packages/libp2p/src/libp2p.ts b/packages/libp2p/src/libp2p.ts index 29c80f0cc7..d5c829b142 100644 --- a/packages/libp2p/src/libp2p.ts +++ b/packages/libp2p/src/libp2p.ts @@ -18,8 +18,8 @@ import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { DefaultAddressManager } from './address-manager/index.js' import { defaultComponents } from './components.js' +import { validateConfig } from './config/config.js' import { connectionGater } from './config/connection-gater.js' -import { validateConfig } from './config.js' import { DefaultConnectionManager } from './connection-manager/index.js' import { CompoundContentRouting } from './content-routing/index.js' import { codes } from './errors.js' diff --git a/packages/libp2p/src/ping/index.ts b/packages/libp2p/src/ping/index.ts index 49c813b72e..74491dc267 100644 --- a/packages/libp2p/src/ping/index.ts +++ b/packages/libp2p/src/ping/index.ts @@ -4,6 +4,7 @@ import { logger } from '@libp2p/logger' import first from 'it-first' import { pipe } from 'it-pipe' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { boolean, number, object, string } from 'yup' import { codes } from '../errors.js' import { PROTOCOL_PREFIX, PROTOCOL_NAME, PING_LENGTH, PROTOCOL_VERSION, TIMEOUT, MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS } from './constants.js' import type { AbortOptions } from '@libp2p/interface' @@ -49,11 +50,20 @@ class DefaultPingService implements Startable, PingService { constructor (components: PingServiceComponents, init: PingServiceInit) { this.components = components this.started = false - this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = init.timeout ?? TIMEOUT - this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS - this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS - this.runOnTransientConnection = init.runOnTransientConnection ?? true + + const validatedConfig = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + timeout: number().integer().default(TIMEOUT), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + runOnTransientConnection: boolean().default(true) + }).validateSync(init) + + this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = validatedConfig.timeout + this.maxInboundStreams = validatedConfig.maxInboundStreams + this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.runOnTransientConnection = validatedConfig.runOnTransientConnection } async start (): Promise { diff --git a/packages/libp2p/src/upnp-nat/index.ts b/packages/libp2p/src/upnp-nat/index.ts index 8e422f6b1a..6969263b66 100644 --- a/packages/libp2p/src/upnp-nat/index.ts +++ b/packages/libp2p/src/upnp-nat/index.ts @@ -5,6 +5,7 @@ import { isLoopback } from '@libp2p/utils/multiaddr/is-loopback' import { fromNodeAddress } from '@multiformats/multiaddr' import isPrivateIp from 'private-ip' import { isBrowser } from 'wherearewe' +import { boolean, number, object, string } from 'yup' import { codes } from '../errors.js' import * as pkg from '../version.js' import type { PeerId } from '@libp2p/interface/peer-id' @@ -70,21 +71,32 @@ class UPnPNAT implements Startable { private readonly localAddress?: string private readonly description: string private readonly ttl: number - private readonly keepAlive: boolean + private readonly keepAlive?: boolean private readonly gateway?: string private started: boolean private client?: NatAPI constructor (components: UPnPNATComponents, init: UPnPNATInit) { this.components = components - this.started = false - this.externalAddress = init.externalAddress - this.localAddress = init.localAddress - this.description = init.description ?? `${pkg.name}@${pkg.version} ${this.components.peerId.toString()}` - this.ttl = init.ttl ?? DEFAULT_TTL - this.keepAlive = init.keepAlive ?? true - this.gateway = init.gateway + + const validIPRegex = /^(?:(?:^|\.)(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){4}$/ + + const validatedConfig = object({ + externalAddress: string().matches(validIPRegex, 'Invalid IP address'), + localAddress: string().matches(validIPRegex, 'Invalid IP address'), + description: string().default(`${pkg.name}@${pkg.version} ${this.components.peerId.toString()}`), + ttl: number().integer().default(DEFAULT_TTL), + keepAlive: boolean().default(true), + gateway: string().optional() + }).validateSync(init) + + this.externalAddress = validatedConfig.externalAddress + this.localAddress = validatedConfig.localAddress + this.description = validatedConfig.description + this.ttl = validatedConfig.ttl + this.keepAlive = validatedConfig.keepAlive + this.gateway = validatedConfig.gateway if (this.ttl < DEFAULT_TTL) { throw new CodeError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`, codes.ERR_INVALID_PARAMETERS) diff --git a/packages/libp2p/test/circuit-relay/discovery.node.ts b/packages/libp2p/test/circuit-relay/discovery.node.ts index 19517e67be..b6c434d6d7 100644 --- a/packages/libp2p/test/circuit-relay/discovery.node.ts +++ b/packages/libp2p/test/circuit-relay/discovery.node.ts @@ -5,6 +5,7 @@ import { tcp } from '@libp2p/tcp' import { expect } from 'aegir/chai' import { pEvent } from 'p-event' import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '../../src/circuit-relay/index.js' +import { identifyService } from '../../src/identify/index.js' import { createLibp2p } from '../../src/index.js' import { plaintext } from '../../src/insecure/index.js' import { getRelayAddress, hasRelay, MockContentRouting, mockContentRouting } from './utils.js' @@ -34,6 +35,7 @@ describe('circuit-relay discovery', () => { mockContentRouting() ], services: { + identify: identifyService(), relay: circuitRelayServer({ advertise: { bootDelay: 10 diff --git a/packages/libp2p/test/configuration/protocol-prefix.node.ts b/packages/libp2p/test/configuration/protocol-prefix.node.ts index db4ecea61c..93eb2af4f5 100644 --- a/packages/libp2p/test/configuration/protocol-prefix.node.ts +++ b/packages/libp2p/test/configuration/protocol-prefix.node.ts @@ -67,7 +67,8 @@ describe('Protocol prefix is configurable', () => { '/ipfs/id/1.0.0', '/ipfs/id/push/1.0.0', '/ipfs/ping/1.0.0', - '/libp2p/fetch/0.0.1' + '/libp2p/fetch/0.0.1', + '/libp2p/circuit/relay/0.2.0/stop' ]) }) }) diff --git a/packages/libp2p/test/connection-manager/index.node.ts b/packages/libp2p/test/connection-manager/index.node.ts index add7158a47..9a45635f4d 100644 --- a/packages/libp2p/test/connection-manager/index.node.ts +++ b/packages/libp2p/test/connection-manager/index.node.ts @@ -235,7 +235,9 @@ describe('libp2p.connections', () => { }, connectionManager: { minConnections, - maxConnections: 1 + maxConnections: 1, + inboundConnectionThreshold: 1, + maxIncomingPendingConnections: 1 } } }) diff --git a/packages/libp2p/test/connection-manager/index.spec.ts b/packages/libp2p/test/connection-manager/index.spec.ts index 699339da03..4189969895 100644 --- a/packages/libp2p/test/connection-manager/index.spec.ts +++ b/packages/libp2p/test/connection-manager/index.spec.ts @@ -77,7 +77,9 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 2 + minConnections: 2, + inboundConnectionThreshold: max, + maxIncomingPendingConnections: max } }), started: false @@ -136,7 +138,9 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 2 + minConnections: 2, + maxIncomingPendingConnections: max, + inboundConnectionThreshold: max } }), started: false @@ -202,6 +206,8 @@ describe('Connection Manager', () => { connectionManager: { maxConnections: max, minConnections: 0, + maxIncomingPendingConnections: max, + inboundConnectionThreshold: max, allow: [ '/ip4/83.13.55.32' ] @@ -286,7 +292,9 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 0 + minConnections: 0, + maxIncomingPendingConnections: max, + inboundConnectionThreshold: max } }), started: false @@ -319,11 +327,13 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: 5, - minConnections: 6 + minConnections: 6, + maxIncomingPendingConnections: 5, + inboundConnectionThreshold: 5 } }), started: false - })).to.eventually.rejected('maxConnections must be greater') + })).to.eventually.rejectedWith('minConnections must be less than the max connections limit: 5') }) it('should reconnect to important peers on startup', async () => { diff --git a/packages/libp2p/test/connection-manager/resolver.spec.ts b/packages/libp2p/test/connection-manager/resolver.spec.ts index adccf3976d..ef8ed7f905 100644 --- a/packages/libp2p/test/connection-manager/resolver.spec.ts +++ b/packages/libp2p/test/connection-manager/resolver.spec.ts @@ -14,6 +14,7 @@ import sinon from 'sinon' import { RELAY_V2_HOP_CODEC } from '../../src/circuit-relay/constants.js' import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '../../src/circuit-relay/index.js' import { codes as ErrorCodes } from '../../src/errors.js' +import { identifyService } from '../../src/identify/index.js' import { plaintext } from '../../src/insecure/index.js' import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' import type { PeerId } from '@libp2p/interface/peer-id' @@ -93,7 +94,8 @@ describe('dialing (resolvable addresses)', () => { plaintext() ], services: { - relay: circuitRelayServer() + relay: circuitRelayServer(), + identify: identifyService() }, connectionGater: mockConnectionGater() }) diff --git a/packages/libp2p/test/ping/ping.node.ts b/packages/libp2p/test/ping/ping.node.ts index aba6537aa7..6c5e0f299e 100644 --- a/packages/libp2p/test/ping/ping.node.ts +++ b/packages/libp2p/test/ping/ping.node.ts @@ -4,6 +4,7 @@ import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import { pipe } from 'it-pipe' import pDefer from 'p-defer' +import { identifyService } from '../../src/identify/index.js' import { PROTOCOL } from '../../src/ping/constants.js' import { pingService, type PingService } from '../../src/ping/index.js' import { createBaseOptions } from '../fixtures/base-options.js' @@ -18,6 +19,7 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { + identify: identifyService(), ping: pingService() } }) @@ -25,6 +27,7 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { + identify: identifyService(), ping: pingService() } }) @@ -32,6 +35,7 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { + identify: identifyService(), ping: pingService() } }) @@ -106,6 +110,7 @@ describe('ping', () => { const client = await createNode({ config: createBaseOptions({ services: { + identify: identifyService(), ping: pingService({ // Allow two outbound ping streams. // It is not allowed by the spec, but this test needs to open two concurrent streams. diff --git a/packages/transport-webrtc/.aegir.js b/packages/transport-webrtc/.aegir.js index 491576df87..dfbb5439dc 100644 --- a/packages/transport-webrtc/.aegir.js +++ b/packages/transport-webrtc/.aegir.js @@ -1,4 +1,3 @@ - /** @type {import('aegir').PartialOptions} */ export default { build: { @@ -32,7 +31,7 @@ export default { services: { relay: circuitRelayServer({ reservations: { - maxReservations: Infinity + maxReservations: 10000 } }), identify: identifyService() From 80fd92e19133708cad2673b86de6eb9921fc9df9 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 21:46:13 -0500 Subject: [PATCH 02/15] refactor: updated functions according to pr comments --- packages/libp2p/src/autonat/index.ts | 24 +++++++------ .../libp2p/src/circuit-relay/server/index.ts | 28 ++++++++------- .../circuit-relay/server/reservation-store.ts | 17 +++++----- .../src/circuit-relay/transport/index.ts | 14 ++++---- packages/libp2p/src/config/config.ts | 10 +----- .../libp2p/src/connection-manager/utils.ts | 6 ++-- packages/libp2p/src/dcutr/dcutr.ts | 20 ++++++----- packages/libp2p/src/fetch/constants.ts | 2 +- packages/libp2p/src/fetch/index.ts | 18 +++++----- packages/libp2p/src/identify/identify.ts | 34 ++++++++++--------- packages/libp2p/src/ping/index.ts | 18 +++++----- packages/libp2p/src/upnp-nat/index.ts | 24 +++++++------ .../configuration/protocol-prefix.node.ts | 3 +- .../test/connection-manager/index.spec.ts | 20 +++-------- .../test/connection-manager/resolver.spec.ts | 4 +-- packages/libp2p/test/ping/ping.node.ts | 5 --- 16 files changed, 119 insertions(+), 128 deletions(-) diff --git a/packages/libp2p/src/autonat/index.ts b/packages/libp2p/src/autonat/index.ts index 319493d39b..ab220d749d 100644 --- a/packages/libp2p/src/autonat/index.ts +++ b/packages/libp2p/src/autonat/index.ts @@ -97,6 +97,15 @@ export interface AutoNATComponents { peerRouting: PeerRouting } +const configValidator = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + timeout: number().integer().default(TIMEOUT), + startupDelay: number().integer().default(STARTUP_DELAY), + refreshInterval: number().integer().default(REFRESH_INTERVAL), + maxInboundStreams: number().integer().default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().default(MAX_OUTBOUND_STREAMS) +}) + class DefaultAutoNATService implements Startable { private readonly components: AutoNATComponents private readonly startupDelay: number @@ -109,14 +118,7 @@ class DefaultAutoNATService implements Startable { private started: boolean constructor (components: AutoNATComponents, init: AutoNATServiceInit) { - const validatedConfig = object({ - protocolPrefix: string().default(PROTOCOL_PREFIX), - timeout: number().integer().default(TIMEOUT), - startupDelay: number().integer().default(STARTUP_DELAY), - refreshInterval: number().integer().default(REFRESH_INTERVAL), - maxInboundStreams: number().integer().default(MAX_INBOUND_STREAMS), - maxOutboundStreams: number().integer().default(MAX_OUTBOUND_STREAMS) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.components = components this.started = false @@ -177,7 +179,7 @@ class DefaultAutoNATService implements Startable { try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } const ourHosts = this.components.addressManager.getAddresses() .map(ma => ma.toOptions().host) @@ -445,7 +447,7 @@ class DefaultAutoNATService implements Startable { try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } const self = this @@ -469,7 +471,7 @@ class DefaultAutoNATService implements Startable { const networkSegments: string[] = [] const verifyAddress = async (peer: PeerInfo): Promise => { - let onAbort = (): void => {} + let onAbort = (): void => { } try { log('asking %p to verify multiaddr', peer.id) diff --git a/packages/libp2p/src/circuit-relay/server/index.ts b/packages/libp2p/src/circuit-relay/server/index.ts index 758db09e4d..9e465b3b67 100644 --- a/packages/libp2p/src/circuit-relay/server/index.ts +++ b/packages/libp2p/src/circuit-relay/server/index.ts @@ -101,6 +101,20 @@ export interface RelayServerEvents { 'relay:advert:error': CustomEvent } +const configValidator = object({ + hopTimeout: number().min(0).integer().default(DEFAULT_HOP_TIMEOUT), + reservations: object({ + maxReservations: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_STORE_SIZE), + reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), + applyDefaultLimit: boolean().default(false), + reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), + defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT) + }), + maxInboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_INBOUND_STREAMS), + maxOutboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_OUTBOUND_STREAMS), + maxOutboundStopStreams: number().integer().min(0).default(MAX_CONNECTIONS) +}) + class CircuitRelayServer extends EventEmitter implements Startable, CircuitRelayService { private readonly registrar: Registrar private readonly peerStore: PeerStore @@ -123,19 +137,7 @@ class CircuitRelayServer extends EventEmitter implements Star constructor (components: CircuitRelayServerComponents, init: CircuitRelayServerInit = {}) { super() - const validatedConfig = object({ - hopTimeout: number().min(0).integer().default(DEFAULT_HOP_TIMEOUT), - reservations: object({ - maxReservations: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_STORE_SIZE), - reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), - applyDefaultLimit: boolean().default(true), - reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), - defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT).max(init?.reservations?.reservationTtl ?? DEFAULT_MAX_RESERVATION_TTL, `default duration limit must be less than reservation TTL: ${init?.reservations?.reservationTtl}`) - }), - maxInboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_INBOUND_STREAMS), - maxOutboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_OUTBOUND_STREAMS), - maxOutboundStopStreams: number().integer().min(0).default(MAX_CONNECTIONS) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.registrar = components.registrar this.peerStore = components.peerStore diff --git a/packages/libp2p/src/circuit-relay/server/reservation-store.ts b/packages/libp2p/src/circuit-relay/server/reservation-store.ts index 36a747c99c..4c6ae145f4 100644 --- a/packages/libp2p/src/circuit-relay/server/reservation-store.ts +++ b/packages/libp2p/src/circuit-relay/server/reservation-store.ts @@ -39,6 +39,14 @@ export interface ReservationStoreInit { export type ReservationStoreOptions = RecursivePartial +const configValidator = object({ + maxReservations: number().min(0).integer().default(DEFAULT_MAX_RESERVATION_STORE_SIZE), + reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), + applyDefaultLimit: boolean().default(true), + reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), + defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT), + defaultDataLimit: mixed().test('is-bigint', 'Invalid bigint', value => typeof value === 'bigint').default(DEFAULT_DATA_LIMIT) +}) export class ReservationStore implements Startable { public readonly reservations = new PeerMap() private _started = false @@ -51,14 +59,7 @@ export class ReservationStore implements Startable { private readonly defaultDataLimit: bigint constructor (options: ReservationStoreOptions = {}) { - const validatedConfig = object({ - maxReservations: number().min(0).integer().default(DEFAULT_MAX_RESERVATION_STORE_SIZE), - reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), - applyDefaultLimit: boolean().default(true), - reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), - defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT), - defaultDataLimit: mixed().test('is-bigint', 'Invalid bigint', value => typeof value === 'bigint').default(DEFAULT_DATA_LIMIT) - }).validateSync(options) + const validatedConfig = configValidator.validateSync(options) this.maxReservations = validatedConfig.maxReservations this.reservationClearInterval = validatedConfig.reservationClearInterval diff --git a/packages/libp2p/src/circuit-relay/transport/index.ts b/packages/libp2p/src/circuit-relay/transport/index.ts index 6125c55b20..60e6283bec 100644 --- a/packages/libp2p/src/circuit-relay/transport/index.ts +++ b/packages/libp2p/src/circuit-relay/transport/index.ts @@ -101,6 +101,13 @@ export interface CircuitRelayTransportInit extends RelayStoreInit { reservationCompletionTimeout?: number } +const configValidator = object({ + discoverRelays: number().min(0).integer().default(0), + maxInboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + maxOutboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + stopTimeout: number().min(0).integer().default(DEFAULT_STOP_TIMEOUT) +}) + class CircuitRelayTransport implements Transport { private readonly discovery?: RelayDiscovery private readonly registrar: Registrar @@ -117,12 +124,7 @@ class CircuitRelayTransport implements Transport { private started: boolean constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) { - const validatedConfig = object({ - discoverRelays: number().min(0).integer().default(0), - maxInboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), - maxOutboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), - stopTimeout: number().min(0).integer().default(DEFAULT_STOP_TIMEOUT) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.registrar = components.registrar this.peerStore = components.peerStore diff --git a/packages/libp2p/src/config/config.ts b/packages/libp2p/src/config/config.ts index fb928825eb..10045aa9f8 100644 --- a/packages/libp2p/src/config/config.ts +++ b/packages/libp2p/src/config/config.ts @@ -22,20 +22,12 @@ const DefaultConfig: Partial = { } } -export function validateConfig > (opts: RecursivePartial>): Libp2pInit { +export function validateConfig> (opts: RecursivePartial>): Libp2pInit { const libp2pConfig = object({ addresses: validateAddressManagerConfig(opts?.addresses as AddressManagerInit), connectionManager: validateConnectionManagerConfig(opts?.connectionManager as ConnectionManagerInit) }) - if ((opts?.services) != null) { - // @ts-expect-error until we resolve https://github.com/libp2p/js-libp2p/pull/1762 and have a better way of discovering type dependencies - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if ((opts.services?.kadDHT || opts.services?.relay || opts.services?.ping) && !opts.services.identify) { - throw new Error('identify service is required when using kadDHT, relay, or ping') - } - } - const parsedOpts = libp2pConfig.validateSync(opts) const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, parsedOpts) diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 760461beab..52804bb21b 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -73,7 +73,7 @@ export function combineSignals (...signals: Array): Cle try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } return signal } @@ -92,7 +92,7 @@ export const validateConnectionManagerConfig = (opts: ConnectionManagerInit): Ob inboundUpgradeTimeout: number().integer().default(INBOUND_UPGRADE_TIMEOUT), allow: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), deny: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), - inboundConnectionThreshold: number().max(opts?.maxConnections ?? MAX_CONNECTIONS, `inboundConnectionThreshold must be less than the max connections limit: ${opts?.inboundConnectionThreshold}`).integer().default(INBOUND_CONNECTION_THRESHOLD), - maxIncomingPendingConnections: number().integer().max(opts?.maxConnections ?? MAX_CONNECTIONS, `maxIncomingPendingConnections must be less than the max connections limit: ${opts?.maxIncomingPendingConnections}`).default(MAX_INCOMING_PENDING_CONNECTIONS) + inboundConnectionThreshold: number().integer().default(INBOUND_CONNECTION_THRESHOLD), + maxIncomingPendingConnections: number().integer().default(MAX_INCOMING_PENDING_CONNECTIONS) }) } diff --git a/packages/libp2p/src/dcutr/dcutr.ts b/packages/libp2p/src/dcutr/dcutr.ts index c505b10e51..2c7693b697 100644 --- a/packages/libp2p/src/dcutr/dcutr.ts +++ b/packages/libp2p/src/dcutr/dcutr.ts @@ -25,6 +25,15 @@ const MAX_DCUTR_MESSAGE_SIZE = 1024 * 4 // ensure the dial has a high priority to jump to the head of the dial queue const DCUTR_DIAL_PRIORITY = 100 +const configValidator = object({ + // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 + timeout: number().integer().default(5000).min(1), + // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 + retries: number().integer().default(3).min(1), + maxInboundStreams: number().integer().default(1).min(1), + maxOutboundStreams: number().integer().default(1).min(1) +}) + export class DefaultDCUtRService implements Startable { private started: boolean private readonly timeout: number @@ -46,14 +55,7 @@ export class DefaultDCUtRService implements Startable { this.connectionManager = components.connectionManager this.transportManager = components.transportManager - const validatedConfig = object({ - // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 - timeout: number().integer().default(5000).min(1), - // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 - retries: number().integer().default(3).min(1), - maxInboundStreams: number().integer().default(1).min(1), - maxOutboundStreams: number().integer().default(1).min(1) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.timeout = validatedConfig.timeout this.retries = validatedConfig.retries @@ -371,7 +373,7 @@ export class DefaultDCUtRService implements Startable { } output.push(ma) - } catch {} + } catch { } } return output diff --git a/packages/libp2p/src/fetch/constants.ts b/packages/libp2p/src/fetch/constants.ts index d0be9327b2..c55751f43c 100644 --- a/packages/libp2p/src/fetch/constants.ts +++ b/packages/libp2p/src/fetch/constants.ts @@ -4,4 +4,4 @@ export const PROTOCOL_NAME = 'fetch' export const MAX_INBOUND_STREAMS = 1 export const MAX_OUTBOUND_STREAMS = 1 -export const TIMEOUT = 60000 +export const TIMEOUT = 10000 diff --git a/packages/libp2p/src/fetch/index.ts b/packages/libp2p/src/fetch/index.ts index c5e2e69baf..ce6fdec2c5 100644 --- a/packages/libp2p/src/fetch/index.ts +++ b/packages/libp2p/src/fetch/index.ts @@ -82,6 +82,13 @@ export interface FetchService { unregisterLookupFunction(prefix: string, lookup?: LookupFunction): void } +const configValidator = object({ + protocolPrefix: string().default('libp2p'), + timeout: number().integer().default(TIMEOUT), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) +}) + /** * A simple libp2p protocol for requesting a value corresponding to a key from a peer. * Developers can register one or more lookup function for retrieving the value corresponding to @@ -98,12 +105,7 @@ class DefaultFetchService implements Startable, FetchService { private readonly maxOutboundStreams: number constructor (components: FetchServiceComponents, init: FetchServiceInit) { - const validatedConfig = object({ - protocolPrefix: string().default('libp2p'), - timeout: number().integer().default(TIMEOUT), - maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), - maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.started = false this.components = components @@ -150,7 +152,7 @@ class DefaultFetchService implements Startable, FetchService { const connection = await this.components.connectionManager.openConnection(peer, options) let signal = options.signal let stream: Stream | undefined - let onAbort = (): void => {} + let onAbort = (): void => { } // create a timeout if no abort signal passed if (signal == null) { @@ -160,7 +162,7 @@ class DefaultFetchService implements Startable, FetchService { try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } } try { diff --git a/packages/libp2p/src/identify/identify.ts b/packages/libp2p/src/identify/identify.ts index 3e992da045..9fc515f5e0 100644 --- a/packages/libp2p/src/identify/identify.ts +++ b/packages/libp2p/src/identify/identify.ts @@ -42,6 +42,20 @@ import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/r const log = logger('libp2p:identify') +const configValidator = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + agentVersion: string().default(AGENT_VERSION), + timeout: number().integer().default(TIMEOUT), + maxIdentifyMessageSize: number().integer().min(0).default(MAX_IDENTIFY_MESSAGE_SIZE), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxPushIncomingStreams: number().integer().min(0).default(MAX_PUSH_INCOMING_STREAMS), + maxPushOutgoingStreams: number().integer().min(0).default(MAX_PUSH_OUTGOING_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + maxObservedAddresses: number().integer().min(0).default(MAX_OBSERVED_ADDRESSES), + runOnConnectionOpen: boolean().default(RUN_ON_CONNECTION_OPEN), + runOnTransientConnection: boolean().default(RUN_ON_TRANSIENT_CONNECTION) +}) + export class DefaultIdentifyService implements Startable, IdentifyService { private readonly identifyProtocolStr: string private readonly identifyPushProtocolStr: string @@ -68,19 +82,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { private readonly runOnConnectionOpen: boolean constructor (components: IdentifyServiceComponents, init: IdentifyServiceInit) { - const validatedConfig = object({ - protocolPrefix: string().default(PROTOCOL_PREFIX), - agentVersion: string().default(AGENT_VERSION), - timeout: number().integer().default(TIMEOUT), - maxIdentifyMessageSize: number().integer().min(0).default(MAX_IDENTIFY_MESSAGE_SIZE), - maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), - maxPushIncomingStreams: number().integer().min(0).default(MAX_PUSH_INCOMING_STREAMS), - maxPushOutgoingStreams: number().integer().min(0).default(MAX_PUSH_OUTGOING_STREAMS), - maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), - maxObservedAddresses: number().integer().min(0).default(MAX_OBSERVED_ADDRESSES), - runOnConnectionOpen: boolean().default(RUN_ON_CONNECTION_OPEN), - runOnTransientConnection: boolean().default(RUN_ON_TRANSIENT_CONNECTION) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.started = false this.peerId = components.peerId @@ -199,7 +201,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } try { stream = await connection.newStream([this.identifyPushProtocolStr], { @@ -322,7 +324,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { log('our observed address is %a', cleanObservedAddr) if (cleanObservedAddr != null && - this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses)) { + this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses)) { log('storing our observed address %a', cleanObservedAddr) this.addressManager.addObservedAddr(cleanObservedAddr) } @@ -357,7 +359,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { try { // fails on node < 15.4 setMaxListeners?.(Infinity, signal) - } catch {} + } catch { } try { const publicKey = this.peerId.publicKey ?? new Uint8Array(0) diff --git a/packages/libp2p/src/ping/index.ts b/packages/libp2p/src/ping/index.ts index e07ea0025c..19d3598d87 100644 --- a/packages/libp2p/src/ping/index.ts +++ b/packages/libp2p/src/ping/index.ts @@ -38,6 +38,14 @@ export interface PingServiceComponents { connectionManager: ConnectionManager } +const configValidator = object({ + protocolPrefix: string().default(PROTOCOL_PREFIX), + timeout: number().integer().default(TIMEOUT), + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + runOnTransientConnection: boolean().default(true) +}) + class DefaultPingService implements Startable, PingService { public readonly protocol: string private readonly components: PingServiceComponents @@ -51,13 +59,7 @@ class DefaultPingService implements Startable, PingService { this.components = components this.started = false - const validatedConfig = object({ - protocolPrefix: string().default(PROTOCOL_PREFIX), - timeout: number().integer().default(TIMEOUT), - maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), - maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), - runOnTransientConnection: boolean().default(true) - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` this.timeout = validatedConfig.timeout @@ -117,7 +119,7 @@ class DefaultPingService implements Startable, PingService { const data = randomBytes(PING_LENGTH) const connection = await this.components.connectionManager.openConnection(peer, options) let stream: Stream | undefined - let onAbort = (): void => {} + let onAbort = (): void => { } options.signal = options.signal ?? AbortSignal.timeout(this.timeout) diff --git a/packages/libp2p/src/upnp-nat/index.ts b/packages/libp2p/src/upnp-nat/index.ts index 6969263b66..51bb1bd1f3 100644 --- a/packages/libp2p/src/upnp-nat/index.ts +++ b/packages/libp2p/src/upnp-nat/index.ts @@ -65,6 +65,17 @@ export interface UPnPNATComponents { addressManager: AddressManager } +const validIPRegex = /^(?:(?:^|\.)(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){4}$/ + +const configValidator = object({ + externalAddress: string().matches(validIPRegex, 'Invalid IP address'), + localAddress: string().matches(validIPRegex, 'Invalid IP address'), + description: string(), + ttl: number().integer().default(DEFAULT_TTL), + keepAlive: boolean().default(true), + gateway: string().optional() +}) + class UPnPNAT implements Startable { private readonly components: UPnPNATComponents private readonly externalAddress?: string @@ -80,20 +91,11 @@ class UPnPNAT implements Startable { this.components = components this.started = false - const validIPRegex = /^(?:(?:^|\.)(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){4}$/ - - const validatedConfig = object({ - externalAddress: string().matches(validIPRegex, 'Invalid IP address'), - localAddress: string().matches(validIPRegex, 'Invalid IP address'), - description: string().default(`${pkg.name}@${pkg.version} ${this.components.peerId.toString()}`), - ttl: number().integer().default(DEFAULT_TTL), - keepAlive: boolean().default(true), - gateway: string().optional() - }).validateSync(init) + const validatedConfig = configValidator.validateSync(init) this.externalAddress = validatedConfig.externalAddress this.localAddress = validatedConfig.localAddress - this.description = validatedConfig.description + this.description = validatedConfig.description ?? `${pkg.name}@${pkg.version} ${this.components.peerId.toString()}` this.ttl = validatedConfig.ttl this.keepAlive = validatedConfig.keepAlive this.gateway = validatedConfig.gateway diff --git a/packages/libp2p/test/configuration/protocol-prefix.node.ts b/packages/libp2p/test/configuration/protocol-prefix.node.ts index 93eb2af4f5..db4ecea61c 100644 --- a/packages/libp2p/test/configuration/protocol-prefix.node.ts +++ b/packages/libp2p/test/configuration/protocol-prefix.node.ts @@ -67,8 +67,7 @@ describe('Protocol prefix is configurable', () => { '/ipfs/id/1.0.0', '/ipfs/id/push/1.0.0', '/ipfs/ping/1.0.0', - '/libp2p/fetch/0.0.1', - '/libp2p/circuit/relay/0.2.0/stop' + '/libp2p/fetch/0.0.1' ]) }) }) diff --git a/packages/libp2p/test/connection-manager/index.spec.ts b/packages/libp2p/test/connection-manager/index.spec.ts index 4189969895..699339da03 100644 --- a/packages/libp2p/test/connection-manager/index.spec.ts +++ b/packages/libp2p/test/connection-manager/index.spec.ts @@ -77,9 +77,7 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 2, - inboundConnectionThreshold: max, - maxIncomingPendingConnections: max + minConnections: 2 } }), started: false @@ -138,9 +136,7 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 2, - maxIncomingPendingConnections: max, - inboundConnectionThreshold: max + minConnections: 2 } }), started: false @@ -206,8 +202,6 @@ describe('Connection Manager', () => { connectionManager: { maxConnections: max, minConnections: 0, - maxIncomingPendingConnections: max, - inboundConnectionThreshold: max, allow: [ '/ip4/83.13.55.32' ] @@ -292,9 +286,7 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: max, - minConnections: 0, - maxIncomingPendingConnections: max, - inboundConnectionThreshold: max + minConnections: 0 } }), started: false @@ -327,13 +319,11 @@ describe('Connection Manager', () => { config: createBaseOptions({ connectionManager: { maxConnections: 5, - minConnections: 6, - maxIncomingPendingConnections: 5, - inboundConnectionThreshold: 5 + minConnections: 6 } }), started: false - })).to.eventually.rejectedWith('minConnections must be less than the max connections limit: 5') + })).to.eventually.rejected('maxConnections must be greater') }) it('should reconnect to important peers on startup', async () => { diff --git a/packages/libp2p/test/connection-manager/resolver.spec.ts b/packages/libp2p/test/connection-manager/resolver.spec.ts index ef8ed7f905..adccf3976d 100644 --- a/packages/libp2p/test/connection-manager/resolver.spec.ts +++ b/packages/libp2p/test/connection-manager/resolver.spec.ts @@ -14,7 +14,6 @@ import sinon from 'sinon' import { RELAY_V2_HOP_CODEC } from '../../src/circuit-relay/constants.js' import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '../../src/circuit-relay/index.js' import { codes as ErrorCodes } from '../../src/errors.js' -import { identifyService } from '../../src/identify/index.js' import { plaintext } from '../../src/insecure/index.js' import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' import type { PeerId } from '@libp2p/interface/peer-id' @@ -94,8 +93,7 @@ describe('dialing (resolvable addresses)', () => { plaintext() ], services: { - relay: circuitRelayServer(), - identify: identifyService() + relay: circuitRelayServer() }, connectionGater: mockConnectionGater() }) diff --git a/packages/libp2p/test/ping/ping.node.ts b/packages/libp2p/test/ping/ping.node.ts index 6c5e0f299e..aba6537aa7 100644 --- a/packages/libp2p/test/ping/ping.node.ts +++ b/packages/libp2p/test/ping/ping.node.ts @@ -4,7 +4,6 @@ import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import { pipe } from 'it-pipe' import pDefer from 'p-defer' -import { identifyService } from '../../src/identify/index.js' import { PROTOCOL } from '../../src/ping/constants.js' import { pingService, type PingService } from '../../src/ping/index.js' import { createBaseOptions } from '../fixtures/base-options.js' @@ -19,7 +18,6 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { - identify: identifyService(), ping: pingService() } }) @@ -27,7 +25,6 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { - identify: identifyService(), ping: pingService() } }) @@ -35,7 +32,6 @@ describe('ping', () => { createNode({ config: createBaseOptions({ services: { - identify: identifyService(), ping: pingService() } }) @@ -110,7 +106,6 @@ describe('ping', () => { const client = await createNode({ config: createBaseOptions({ services: { - identify: identifyService(), ping: pingService({ // Allow two outbound ping streams. // It is not allowed by the spec, but this test needs to open two concurrent streams. From 5ccd6bfac52becbaed9d8a69a46445e1860e1753 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 9 Oct 2023 12:30:21 -0500 Subject: [PATCH 03/15] chore: ensure inboundConnectionThreshold is a number --- packages/transport-webrtc/.aegir.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transport-webrtc/.aegir.js b/packages/transport-webrtc/.aegir.js index 6cfccd1524..2149964172 100644 --- a/packages/transport-webrtc/.aegir.js +++ b/packages/transport-webrtc/.aegir.js @@ -36,7 +36,7 @@ export default { }, connectionManager: { minConnections: 0, - inboundConnectionThreshold: Infinity + inboundConnectionThreshold: 1000 } }) From 4ece97616d0c011979d36edc38cb8e32f61dfbe9 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 10 Oct 2023 15:51:21 -0500 Subject: [PATCH 04/15] refactor: address PR comments --- .../libp2p/src/circuit-relay/server/index.ts | 2 +- packages/libp2p/src/config/helpers.ts | 4 +++- .../libp2p/src/connection-manager/utils.ts | 23 ++++++++++--------- packages/libp2p/src/dcutr/dcutr.ts | 8 +++---- packages/libp2p/src/fetch/index.ts | 2 +- packages/libp2p/src/identify/identify.ts | 2 +- packages/libp2p/src/ping/index.ts | 2 +- packages/libp2p/src/upnp-nat/index.ts | 2 +- 8 files changed, 24 insertions(+), 21 deletions(-) diff --git a/packages/libp2p/src/circuit-relay/server/index.ts b/packages/libp2p/src/circuit-relay/server/index.ts index 9e465b3b67..8952188c31 100644 --- a/packages/libp2p/src/circuit-relay/server/index.ts +++ b/packages/libp2p/src/circuit-relay/server/index.ts @@ -102,7 +102,7 @@ export interface RelayServerEvents { } const configValidator = object({ - hopTimeout: number().min(0).integer().default(DEFAULT_HOP_TIMEOUT), + hopTimeout: number().integer().min(0).default(DEFAULT_HOP_TIMEOUT), reservations: object({ maxReservations: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_STORE_SIZE), reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), diff --git a/packages/libp2p/src/config/helpers.ts b/packages/libp2p/src/config/helpers.ts index 9cb4106ae8..0cf87f152e 100644 --- a/packages/libp2p/src/config/helpers.ts +++ b/packages/libp2p/src/config/helpers.ts @@ -1,11 +1,13 @@ +import { CodeError } from '@libp2p/interface/errors' import { multiaddr } from '@multiformats/multiaddr' +import { codes } from '../errors.js' export const validateMultiaddr = (value: Array | undefined): boolean => { value?.forEach((addr) => { try { multiaddr(addr) } catch (err) { - throw new Error(`invalid multiaddr: ${addr}`) + throw new CodeError(`invalid multiaddr: ${addr}`, codes.ERR_INVALID_MULTIADDR) } }) return true diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 52804bb21b..f0ec2804f7 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -80,19 +80,20 @@ export function combineSignals (...signals: Array): Cle export const validateConnectionManagerConfig = (opts: ConnectionManagerInit): ObjectSchema> => { return object({ - maxConnections: number().min(opts?.minConnections ?? MIN_CONNECTIONS, `maxConnections must be greater than the min connections limit: ${opts?.minConnections}`).integer().default(MAX_CONNECTIONS), - minConnections: number().min(0).integer().max(opts?.maxConnections ?? MAX_CONNECTIONS, `minConnections must be less than the max connections limit: ${opts?.maxConnections}`).default(MIN_CONNECTIONS), - autoDialInterval: number().min(0).integer().default(AUTO_DIAL_INTERVAL), - autoDialConcurrency: number().min(0).integer().default(AUTO_DIAL_CONCURRENCY), - autoDialPriority: number().min(0).integer().default(AUTO_DIAL_PRIORITY), - maxParallelDials: number().min(0).integer().default(MAX_PARALLEL_DIALS), - maxParallelDialsPerPeer: number().max(opts?.autoDialConcurrency ?? AUTO_DIAL_CONCURRENCY, `maxParallelDialsPerPeer must be less than the min auto dial conccurency limit: ${opts?.autoDialConcurrency}`).default(MAX_PARALLEL_DIALS_PER_PEER), + maxConnections: number().integer().min(opts?.minConnections ?? MIN_CONNECTIONS, `maxConnections must be greater than or equal to minConnections: ${opts?.minConnections ?? MIN_CONNECTIONS}`).default(MAX_CONNECTIONS), + minConnections: number().integer().min(0).max(opts?.maxConnections ?? MAX_CONNECTIONS, `minConnections must be less than or equal to maxConnections : ${opts?.maxConnections ?? MAX_CONNECTIONS}`).default(MIN_CONNECTIONS), + autoDialInterval: number().integer().min(0).default(AUTO_DIAL_INTERVAL), + autoDialConcurrency: number().integer().min(0).default(AUTO_DIAL_CONCURRENCY), + autoDialPriority: number().integer().min(0).default(AUTO_DIAL_PRIORITY), + maxParallelDials: number().integer().min(0).default(MAX_PARALLEL_DIALS), + // #TODO: To be removed https://github.com/libp2p/js-libp2p/issues/2090 + maxParallelDialsPerPeer: number().max(1, 'maxParallelDialsPerPeer is being removed').default(MAX_PARALLEL_DIALS_PER_PEER), maxPeerAddrsToDialed: number().min(0).integer().default(MAX_PEER_ADDRS_TO_DIAL), - dialTimeout: number().min(0).integer().default(DIAL_TIMEOUT), - inboundUpgradeTimeout: number().integer().default(INBOUND_UPGRADE_TIMEOUT), + dialTimeout: number().integer().min(0).default(DIAL_TIMEOUT), + inboundUpgradeTimeout: number().integer().min(0).default(INBOUND_UPGRADE_TIMEOUT), allow: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), deny: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), - inboundConnectionThreshold: number().integer().default(INBOUND_CONNECTION_THRESHOLD), - maxIncomingPendingConnections: number().integer().default(MAX_INCOMING_PENDING_CONNECTIONS) + inboundConnectionThreshold: number().integer().min(0).default(INBOUND_CONNECTION_THRESHOLD), + maxIncomingPendingConnections: number().integer().min(0).default(MAX_INCOMING_PENDING_CONNECTIONS) }) } diff --git a/packages/libp2p/src/dcutr/dcutr.ts b/packages/libp2p/src/dcutr/dcutr.ts index 2c7693b697..79db34c3ba 100644 --- a/packages/libp2p/src/dcutr/dcutr.ts +++ b/packages/libp2p/src/dcutr/dcutr.ts @@ -27,11 +27,11 @@ const DCUTR_DIAL_PRIORITY = 100 const configValidator = object({ // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 - timeout: number().integer().default(5000).min(1), + timeout: number().integer().default(5000).min(0), // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 - retries: number().integer().default(3).min(1), - maxInboundStreams: number().integer().default(1).min(1), - maxOutboundStreams: number().integer().default(1).min(1) + retries: number().integer().default(3).min(0), + maxInboundStreams: number().integer().default(1).min(0), + maxOutboundStreams: number().integer().default(1).min(0) }) export class DefaultDCUtRService implements Startable { diff --git a/packages/libp2p/src/fetch/index.ts b/packages/libp2p/src/fetch/index.ts index ce6fdec2c5..8bf44fc1ae 100644 --- a/packages/libp2p/src/fetch/index.ts +++ b/packages/libp2p/src/fetch/index.ts @@ -84,7 +84,7 @@ export interface FetchService { const configValidator = object({ protocolPrefix: string().default('libp2p'), - timeout: number().integer().default(TIMEOUT), + timeout: number().integer().min(0).default(TIMEOUT), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) }) diff --git a/packages/libp2p/src/identify/identify.ts b/packages/libp2p/src/identify/identify.ts index 9fc515f5e0..ea74db323f 100644 --- a/packages/libp2p/src/identify/identify.ts +++ b/packages/libp2p/src/identify/identify.ts @@ -45,7 +45,7 @@ const log = logger('libp2p:identify') const configValidator = object({ protocolPrefix: string().default(PROTOCOL_PREFIX), agentVersion: string().default(AGENT_VERSION), - timeout: number().integer().default(TIMEOUT), + timeout: number().integer().min(0).default(TIMEOUT), maxIdentifyMessageSize: number().integer().min(0).default(MAX_IDENTIFY_MESSAGE_SIZE), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), maxPushIncomingStreams: number().integer().min(0).default(MAX_PUSH_INCOMING_STREAMS), diff --git a/packages/libp2p/src/ping/index.ts b/packages/libp2p/src/ping/index.ts index 19d3598d87..8d2eb0b722 100644 --- a/packages/libp2p/src/ping/index.ts +++ b/packages/libp2p/src/ping/index.ts @@ -40,7 +40,7 @@ export interface PingServiceComponents { const configValidator = object({ protocolPrefix: string().default(PROTOCOL_PREFIX), - timeout: number().integer().default(TIMEOUT), + timeout: number().integer().min(0).default(TIMEOUT), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), runOnTransientConnection: boolean().default(true) diff --git a/packages/libp2p/src/upnp-nat/index.ts b/packages/libp2p/src/upnp-nat/index.ts index 51bb1bd1f3..305e61a7f2 100644 --- a/packages/libp2p/src/upnp-nat/index.ts +++ b/packages/libp2p/src/upnp-nat/index.ts @@ -71,7 +71,7 @@ const configValidator = object({ externalAddress: string().matches(validIPRegex, 'Invalid IP address'), localAddress: string().matches(validIPRegex, 'Invalid IP address'), description: string(), - ttl: number().integer().default(DEFAULT_TTL), + ttl: number().integer().min(0).default(DEFAULT_TTL), keepAlive: boolean().default(true), gateway: string().optional() }) From 78a2c4ad5abb67f9fe9fd0831007379e0fc9506a Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 13 Oct 2023 09:28:10 -0500 Subject: [PATCH 05/15] chore: refactor variable name from pr feedback --- packages/libp2p/src/autonat/index.ts | 14 +++++----- .../libp2p/src/circuit-relay/server/index.ts | 10 +++---- .../circuit-relay/server/reservation-store.ts | 16 +++++------ .../src/circuit-relay/transport/index.ts | 10 +++---- packages/libp2p/src/dcutr/dcutr.ts | 10 +++---- packages/libp2p/src/fetch/index.ts | 10 +++---- packages/libp2p/src/identify/identify.ts | 28 +++++++++---------- packages/libp2p/src/ping/index.ts | 12 ++++---- packages/libp2p/src/upnp-nat/index.ts | 16 +++++------ 9 files changed, 63 insertions(+), 63 deletions(-) diff --git a/packages/libp2p/src/autonat/index.ts b/packages/libp2p/src/autonat/index.ts index ab220d749d..637cb26d6a 100644 --- a/packages/libp2p/src/autonat/index.ts +++ b/packages/libp2p/src/autonat/index.ts @@ -118,16 +118,16 @@ class DefaultAutoNATService implements Startable { private started: boolean constructor (components: AutoNATComponents, init: AutoNATServiceInit) { - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) this.components = components this.started = false - this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = validatedConfig.timeout - this.maxInboundStreams = validatedConfig.maxInboundStreams - this.maxOutboundStreams = validatedConfig.maxOutboundStreams - this.startupDelay = validatedConfig.startupDelay - this.refreshInterval = validatedConfig.refreshInterval + this.protocol = `/${config.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = config.timeout + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams + this.startupDelay = config.startupDelay + this.refreshInterval = config.refreshInterval this._verifyExternalAddresses = this._verifyExternalAddresses.bind(this) } diff --git a/packages/libp2p/src/circuit-relay/server/index.ts b/packages/libp2p/src/circuit-relay/server/index.ts index 8952188c31..d173781047 100644 --- a/packages/libp2p/src/circuit-relay/server/index.ts +++ b/packages/libp2p/src/circuit-relay/server/index.ts @@ -137,7 +137,7 @@ class CircuitRelayServer extends EventEmitter implements Star constructor (components: CircuitRelayServerComponents, init: CircuitRelayServerInit = {}) { super() - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) this.registrar = components.registrar this.peerStore = components.peerStore @@ -146,11 +146,11 @@ class CircuitRelayServer extends EventEmitter implements Star this.connectionManager = components.connectionManager this.connectionGater = components.connectionGater this.started = false - this.hopTimeout = validatedConfig.hopTimeout + this.hopTimeout = config.hopTimeout this.shutdownController = new AbortController() - this.maxInboundHopStreams = validatedConfig.maxInboundHopStreams - this.maxOutboundHopStreams = validatedConfig.maxOutboundHopStreams - this.maxOutboundStopStreams = validatedConfig.maxOutboundStopStreams + this.maxInboundHopStreams = config.maxInboundHopStreams + this.maxOutboundHopStreams = config.maxOutboundHopStreams + this.maxOutboundStopStreams = config.maxOutboundStopStreams try { // fails on node < 15.4 diff --git a/packages/libp2p/src/circuit-relay/server/reservation-store.ts b/packages/libp2p/src/circuit-relay/server/reservation-store.ts index 4c6ae145f4..a74850aca3 100644 --- a/packages/libp2p/src/circuit-relay/server/reservation-store.ts +++ b/packages/libp2p/src/circuit-relay/server/reservation-store.ts @@ -59,14 +59,14 @@ export class ReservationStore implements Startable { private readonly defaultDataLimit: bigint constructor (options: ReservationStoreOptions = {}) { - const validatedConfig = configValidator.validateSync(options) - - this.maxReservations = validatedConfig.maxReservations - this.reservationClearInterval = validatedConfig.reservationClearInterval - this.applyDefaultLimit = validatedConfig.applyDefaultLimit - this.reservationTtl = validatedConfig.reservationTtl - this.defaultDurationLimit = validatedConfig.defaultDurationLimit - this.defaultDataLimit = validatedConfig.defaultDataLimit as bigint + const config = configValidator.validateSync(options) + + this.maxReservations = config.maxReservations + this.reservationClearInterval = config.reservationClearInterval + this.applyDefaultLimit = config.applyDefaultLimit + this.reservationTtl = config.reservationTtl + this.defaultDurationLimit = config.defaultDurationLimit + this.defaultDataLimit = config.defaultDataLimit as bigint } isStarted (): boolean { diff --git a/packages/libp2p/src/circuit-relay/transport/index.ts b/packages/libp2p/src/circuit-relay/transport/index.ts index 60e6283bec..a44f3ceccd 100644 --- a/packages/libp2p/src/circuit-relay/transport/index.ts +++ b/packages/libp2p/src/circuit-relay/transport/index.ts @@ -124,7 +124,7 @@ class CircuitRelayTransport implements Transport { private started: boolean constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) { - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) this.registrar = components.registrar this.peerStore = components.peerStore @@ -133,11 +133,11 @@ class CircuitRelayTransport implements Transport { this.upgrader = components.upgrader this.addressManager = components.addressManager this.connectionGater = components.connectionGater - this.maxInboundStopStreams = validatedConfig.maxInboundStopStreams - this.maxOutboundStopStreams = validatedConfig.maxOutboundStopStreams - this.stopTimeout = validatedConfig.stopTimeout + this.maxInboundStopStreams = config.maxInboundStopStreams + this.maxOutboundStopStreams = config.maxOutboundStopStreams + this.stopTimeout = config.stopTimeout - if (validatedConfig.discoverRelays > 0) { + if (config.discoverRelays > 0) { this.discovery = new RelayDiscovery(components) this.discovery.addEventListener('relay:discover', (evt) => { this.reservationStore.addRelay(evt.detail, 'discovered') diff --git a/packages/libp2p/src/dcutr/dcutr.ts b/packages/libp2p/src/dcutr/dcutr.ts index 79db34c3ba..211e817d65 100644 --- a/packages/libp2p/src/dcutr/dcutr.ts +++ b/packages/libp2p/src/dcutr/dcutr.ts @@ -55,12 +55,12 @@ export class DefaultDCUtRService implements Startable { this.connectionManager = components.connectionManager this.transportManager = components.transportManager - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) - this.timeout = validatedConfig.timeout - this.retries = validatedConfig.retries - this.maxInboundStreams = validatedConfig.maxInboundStreams - this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.timeout = config.timeout + this.retries = config.retries + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams } isStarted (): boolean { diff --git a/packages/libp2p/src/fetch/index.ts b/packages/libp2p/src/fetch/index.ts index 8bf44fc1ae..de1b04a298 100644 --- a/packages/libp2p/src/fetch/index.ts +++ b/packages/libp2p/src/fetch/index.ts @@ -105,14 +105,14 @@ class DefaultFetchService implements Startable, FetchService { private readonly maxOutboundStreams: number constructor (components: FetchServiceComponents, init: FetchServiceInit) { - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) this.started = false this.components = components - this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = validatedConfig.timeout - this.maxInboundStreams = validatedConfig.maxInboundStreams - this.maxOutboundStreams = validatedConfig.maxOutboundStreams + this.protocol = `/${config.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = config.timeout + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams this.lookupFunctions = new Map() // Maps key prefix to value lookup function this.handleMessage = this.handleMessage.bind(this) diff --git a/packages/libp2p/src/identify/identify.ts b/packages/libp2p/src/identify/identify.ts index ea74db323f..48503377c9 100644 --- a/packages/libp2p/src/identify/identify.ts +++ b/packages/libp2p/src/identify/identify.ts @@ -82,7 +82,7 @@ export class DefaultIdentifyService implements Startable, IdentifyService { private readonly runOnConnectionOpen: boolean constructor (components: IdentifyServiceComponents, init: IdentifyServiceInit) { - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) this.started = false this.peerId = components.peerId @@ -92,22 +92,22 @@ export class DefaultIdentifyService implements Startable, IdentifyService { this.connectionManager = components.connectionManager this.events = components.events - this.identifyProtocolStr = `/${validatedConfig.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}` - this.identifyPushProtocolStr = `/${validatedConfig.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}` - this.timeout = validatedConfig.timeout - this.maxInboundStreams = validatedConfig.maxInboundStreams - this.maxOutboundStreams = validatedConfig.maxOutboundStreams - this.maxPushIncomingStreams = validatedConfig.maxPushIncomingStreams - this.maxPushOutgoingStreams = validatedConfig.maxPushOutgoingStreams - this.maxIdentifyMessageSize = validatedConfig.maxIdentifyMessageSize - this.maxObservedAddresses = validatedConfig.maxObservedAddresses - this.runOnTransientConnection = validatedConfig.runOnTransientConnection - this.runOnConnectionOpen = validatedConfig.runOnConnectionOpen + this.identifyProtocolStr = `/${config.protocolPrefix}/${MULTICODEC_IDENTIFY_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PROTOCOL_VERSION}` + this.identifyPushProtocolStr = `/${config.protocolPrefix}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME}/${MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION}` + this.timeout = config.timeout + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams + this.maxPushIncomingStreams = config.maxPushIncomingStreams + this.maxPushOutgoingStreams = config.maxPushOutgoingStreams + this.maxIdentifyMessageSize = config.maxIdentifyMessageSize + this.maxObservedAddresses = config.maxObservedAddresses + this.runOnTransientConnection = config.runOnTransientConnection + this.runOnConnectionOpen = config.runOnConnectionOpen // Store self host metadata this.host = { - protocolVersion: `${validatedConfig.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`, - agentVersion: validatedConfig.agentVersion + protocolVersion: `${config.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`, + agentVersion: config.agentVersion } if (this.runOnConnectionOpen) { diff --git a/packages/libp2p/src/ping/index.ts b/packages/libp2p/src/ping/index.ts index 8d2eb0b722..71307fbf92 100644 --- a/packages/libp2p/src/ping/index.ts +++ b/packages/libp2p/src/ping/index.ts @@ -59,13 +59,13 @@ class DefaultPingService implements Startable, PingService { this.components = components this.started = false - const validatedConfig = configValidator.validateSync(init) + const config = configValidator.validateSync(init) - this.protocol = `/${validatedConfig.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = validatedConfig.timeout - this.maxInboundStreams = validatedConfig.maxInboundStreams - this.maxOutboundStreams = validatedConfig.maxOutboundStreams - this.runOnTransientConnection = validatedConfig.runOnTransientConnection + this.protocol = `/${config.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = config.timeout + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams + this.runOnTransientConnection = config.runOnTransientConnection } async start (): Promise { diff --git a/packages/libp2p/src/upnp-nat/index.ts b/packages/libp2p/src/upnp-nat/index.ts index 305e61a7f2..362d997170 100644 --- a/packages/libp2p/src/upnp-nat/index.ts +++ b/packages/libp2p/src/upnp-nat/index.ts @@ -91,14 +91,14 @@ class UPnPNAT implements Startable { this.components = components this.started = false - const validatedConfig = configValidator.validateSync(init) - - this.externalAddress = validatedConfig.externalAddress - this.localAddress = validatedConfig.localAddress - this.description = validatedConfig.description ?? `${pkg.name}@${pkg.version} ${this.components.peerId.toString()}` - this.ttl = validatedConfig.ttl - this.keepAlive = validatedConfig.keepAlive - this.gateway = validatedConfig.gateway + const config = configValidator.validateSync(init) + + this.externalAddress = config.externalAddress + this.localAddress = config.localAddress + this.description = config.description ?? `${pkg.name}@${pkg.version} ${this.components.peerId.toString()}` + this.ttl = config.ttl + this.keepAlive = config.keepAlive + this.gateway = config.gateway if (this.ttl < DEFAULT_TTL) { throw new CodeError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`, codes.ERR_INVALID_PARAMETERS) From cba7c2faf64034958f2098a656ca2c15aed24ea1 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 20 Nov 2023 17:13:03 -0500 Subject: [PATCH 06/15] refactor: updated config validation --- .../test/circuit-relay-discovery.node.ts | 3 +- .../libp2p/src/connection-manager/utils.ts | 4 +- packages/protocol-dcutr/src/dcutr.ts | 5 --- packages/protocol-identify/src/consts.ts | 2 + packages/protocol-identify/src/identify.ts | 4 +- packages/protocol-ping/src/ping.ts | 43 ------------------- .../src/constants.ts | 6 +++ .../src/server/index.ts | 2 + .../src/transport/index.ts | 2 +- packages/upnp-nat/src/upnp-nat.ts | 2 + 10 files changed, 20 insertions(+), 53 deletions(-) diff --git a/packages/integration-tests/test/circuit-relay-discovery.node.ts b/packages/integration-tests/test/circuit-relay-discovery.node.ts index b9d84ae12e..2f49fde243 100644 --- a/packages/integration-tests/test/circuit-relay-discovery.node.ts +++ b/packages/integration-tests/test/circuit-relay-discovery.node.ts @@ -2,6 +2,7 @@ import { yamux } from '@chainsafe/libp2p-yamux' import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '@libp2p/circuit-relay-v2' +import { identify } from '@libp2p/identify' import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { expect } from 'aegir/chai' @@ -34,7 +35,7 @@ describe('circuit-relay discovery', () => { mockContentRouting() ], services: { - identify: identifyService(), + identify: identify(), relay: circuitRelayServer({ advertise: { bootDelay: 10 diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 95335707b9..6c3fee1aff 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -2,8 +2,8 @@ import { setMaxListeners } from '@libp2p/interface/events' import { type AbortOptions, multiaddr, type Multiaddr } from '@multiformats/multiaddr' import { type ClearableSignal, anySignal } from 'any-signal' import { type ObjectSchema, array, number, object, string } from 'yup' -import { validateMultiaddr } from '../config/helpers' -import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_INTERVAL, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, INBOUND_UPGRADE_TIMEOUT, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PARALLEL_DIALS_PER_PEER, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants' +import { validateMultiaddr } from '../config/helpers.js' +import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_INTERVAL, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, INBOUND_UPGRADE_TIMEOUT, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PARALLEL_DIALS_PER_PEER, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js' import type { ConnectionManagerInit } from '.' import type { LoggerOptions } from '@libp2p/interface' diff --git a/packages/protocol-dcutr/src/dcutr.ts b/packages/protocol-dcutr/src/dcutr.ts index 1aab8a05c3..e5cadef7c1 100644 --- a/packages/protocol-dcutr/src/dcutr.ts +++ b/packages/protocol-dcutr/src/dcutr.ts @@ -2,12 +2,7 @@ import { CodeError, ERR_INVALID_MESSAGE } from '@libp2p/interface/errors' import { type Multiaddr, multiaddr } from '@multiformats/multiaddr' import delay from 'delay' import { pbStream } from 'it-protobuf-stream' -<<<<<<< HEAD:packages/libp2p/src/dcutr/dcutr.ts -import isPrivate from 'private-ip' import { number, object } from 'yup' -import { codes } from '../errors.js' -======= ->>>>>>> main:packages/protocol-dcutr/src/dcutr.ts import { HolePunch } from './pb/message.js' import { isPublicAndDialable } from './utils.js' import { multicodec } from './index.js' diff --git a/packages/protocol-identify/src/consts.ts b/packages/protocol-identify/src/consts.ts index 0afb45bdf4..4c71740b45 100644 --- a/packages/protocol-identify/src/consts.ts +++ b/packages/protocol-identify/src/consts.ts @@ -2,6 +2,8 @@ export const PROTOCOL_VERSION = 'ipfs/0.1.0' // deprecated export const MULTICODEC_IDENTIFY = '/ipfs/id/1.0.0' // deprecated export const MULTICODEC_IDENTIFY_PUSH = '/ipfs/id/push/1.0.0' // deprecated +export const AGENT_VERSION = 'js-libp2p/1.0.0' + export const PROTOCOL_PREFIX = 'ipfs' export const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8 // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52 export const MAX_INBOUND_STREAMS = 1 diff --git a/packages/protocol-identify/src/identify.ts b/packages/protocol-identify/src/identify.ts index 3be0f48ba3..841328fa01 100644 --- a/packages/protocol-identify/src/identify.ts +++ b/packages/protocol-identify/src/identify.ts @@ -12,6 +12,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe' import { boolean, number, object, string } from 'yup' import { + AGENT_VERSION, IDENTIFY_PROTOCOL_VERSION, MULTICODEC_IDENTIFY_PROTOCOL_NAME, MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME, @@ -77,6 +78,7 @@ export class Identify implements Startable, IdentifyInterface { private readonly maxObservedAddresses: number private readonly events: TypedEventTarget private readonly runOnTransientConnection: boolean + private readonly runOnConnectionOpen: boolean private readonly log: Logger constructor (components: IdentifyComponents, init: IdentifyInit = {}) { @@ -328,7 +330,7 @@ export class Identify implements Startable, IdentifyInterface { if (cleanObservedAddr != null && this.addressManager.getObservedAddrs().length < (this.maxObservedAddresses)) { - log('storing our observed address %a', cleanObservedAddr) + this.log('storing our observed address %a', cleanObservedAddr) this.addressManager.addObservedAddr(cleanObservedAddr) } diff --git a/packages/protocol-ping/src/ping.ts b/packages/protocol-ping/src/ping.ts index c21c7e4e9a..1ffb729d70 100644 --- a/packages/protocol-ping/src/ping.ts +++ b/packages/protocol-ping/src/ping.ts @@ -3,46 +3,16 @@ import { CodeError, ERR_TIMEOUT } from '@libp2p/interface/errors' import first from 'it-first' import { pipe } from 'it-pipe' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' -<<<<<<< HEAD:packages/libp2p/src/ping/index.ts import { boolean, number, object, string } from 'yup' -import { codes } from '../errors.js' -import { PROTOCOL_PREFIX, PROTOCOL_NAME, PING_LENGTH, PROTOCOL_VERSION, TIMEOUT, MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS } from './constants.js' -import type { AbortOptions } from '@libp2p/interface' -======= import { PROTOCOL_PREFIX, PROTOCOL_NAME, PING_LENGTH, PROTOCOL_VERSION, TIMEOUT, MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, ERR_WRONG_PING_ACK } from './constants.js' import type { PingServiceComponents, PingServiceInit, PingService as PingServiceInterface } from './index.js' import type { AbortOptions, Logger } from '@libp2p/interface' ->>>>>>> main:packages/protocol-ping/src/ping.ts import type { Stream } from '@libp2p/interface/connection' import type { PeerId } from '@libp2p/interface/peer-id' import type { Startable } from '@libp2p/interface/startable' import type { IncomingStreamData } from '@libp2p/interface-internal/registrar' import type { Multiaddr } from '@multiformats/multiaddr' -<<<<<<< HEAD:packages/libp2p/src/ping/index.ts -const log = logger('libp2p:ping') - -export interface PingService { - ping(peer: PeerId | Multiaddr | Multiaddr[], options?: AbortOptions): Promise -} - -export interface PingServiceInit { - protocolPrefix?: string - maxInboundStreams?: number - maxOutboundStreams?: number - runOnTransientConnection?: boolean - - /** - * How long we should wait for a ping response - */ - timeout?: number -} - -export interface PingServiceComponents { - registrar: Registrar - connectionManager: ConnectionManager -} - const configValidator = object({ protocolPrefix: string().default(PROTOCOL_PREFIX), timeout: number().integer().min(0).default(TIMEOUT), @@ -51,10 +21,7 @@ const configValidator = object({ runOnTransientConnection: boolean().default(true) }) -class DefaultPingService implements Startable, PingService { -======= export class PingService implements Startable, PingServiceInterface { ->>>>>>> main:packages/protocol-ping/src/ping.ts public readonly protocol: string private readonly components: PingServiceComponents private started: boolean @@ -68,7 +35,6 @@ export class PingService implements Startable, PingServiceInterface { this.components = components this.log = components.logger.forComponent('libp2p:ping') this.started = false -<<<<<<< HEAD:packages/libp2p/src/ping/index.ts const config = configValidator.validateSync(init) @@ -77,15 +43,6 @@ export class PingService implements Startable, PingServiceInterface { this.maxInboundStreams = config.maxInboundStreams this.maxOutboundStreams = config.maxOutboundStreams this.runOnTransientConnection = config.runOnTransientConnection -======= - this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` - this.timeout = init.timeout ?? TIMEOUT - this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS - this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS - this.runOnTransientConnection = init.runOnTransientConnection ?? true - - this.handleMessage = this.handleMessage.bind(this) ->>>>>>> main:packages/protocol-ping/src/ping.ts } async start (): Promise { diff --git a/packages/transport-circuit-relay-v2/src/constants.ts b/packages/transport-circuit-relay-v2/src/constants.ts index 50ed7a1134..10526ae442 100644 --- a/packages/transport-circuit-relay-v2/src/constants.ts +++ b/packages/transport-circuit-relay-v2/src/constants.ts @@ -73,6 +73,12 @@ export const DEFAULT_ADVERT_BOOT_DELAY = 30 * second export const MAX_CONNECTIONS = 300 +export const DEFAULT_MAX_INBOUND_STREAMS = 300 + +export const DEFAULT_MAX_OUTBOUND_STREAMS = 300 + +export const DEFAULT_STOP_TIMEOUT = 30 * second + export const ERR_NO_ROUTERS_AVAILABLE = 'ERR_NO_ROUTERS_AVAILABLE' export const ERR_RELAYED_DIAL = 'ERR_RELAYED_DIAL' export const ERR_HOP_REQUEST_FAILED = 'ERR_HOP_REQUEST_FAILED' diff --git a/packages/transport-circuit-relay-v2/src/server/index.ts b/packages/transport-circuit-relay-v2/src/server/index.ts index 40d7983c96..ef352e7a04 100644 --- a/packages/transport-circuit-relay-v2/src/server/index.ts +++ b/packages/transport-circuit-relay-v2/src/server/index.ts @@ -9,6 +9,8 @@ import { CIRCUIT_PROTO_CODE, DEFAULT_DURATION_LIMIT, DEFAULT_HOP_TIMEOUT, + DEFAULT_MAX_INBOUND_STREAMS, + DEFAULT_MAX_OUTBOUND_STREAMS, DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL, diff --git a/packages/transport-circuit-relay-v2/src/transport/index.ts b/packages/transport-circuit-relay-v2/src/transport/index.ts index e645267bc8..be7f0d41d8 100644 --- a/packages/transport-circuit-relay-v2/src/transport/index.ts +++ b/packages/transport-circuit-relay-v2/src/transport/index.ts @@ -6,7 +6,7 @@ import * as mafmt from '@multiformats/mafmt' import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' import { number, object } from 'yup' -import { CIRCUIT_PROTO_CODE, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' +import { CIRCUIT_PROTO_CODE, DEFAULT_STOP_TIMEOUT, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' import { StopMessage, HopMessage, Status } from '../pb/index.js' import { RelayDiscovery, type RelayDiscoveryComponents } from './discovery.js' import { createListener } from './listener.js' diff --git a/packages/upnp-nat/src/upnp-nat.ts b/packages/upnp-nat/src/upnp-nat.ts index 439f0b561f..a7632baf3d 100644 --- a/packages/upnp-nat/src/upnp-nat.ts +++ b/packages/upnp-nat/src/upnp-nat.ts @@ -25,6 +25,7 @@ const configValidator = object({ keepAlive: boolean().default(true), gateway: string().optional() }) + export class UPnPNAT implements Startable { private readonly components: UPnPNATComponents private readonly externalAddress?: string @@ -49,6 +50,7 @@ export class UPnPNAT implements Startable { this.description = config.description ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${this.components.peerId.toString()}` this.keepAlive = config.keepAlive this.gateway = config.gateway + this.ttl = config.ttl if (this.ttl < DEFAULT_TTL) { throw new CodeError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`, ERR_INVALID_PARAMETERS) From 355824dadb6debd962f00a0415a2fc540a270478 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 20 Nov 2023 21:39:24 -0500 Subject: [PATCH 07/15] deps: add yup as dep --- packages/protocol-autonat/package.json | 3 +- packages/protocol-dcutr/package.json | 3 +- packages/protocol-fetch/package.json | 3 +- packages/protocol-fetch/src/fetch.ts | 32 +++++++++++++------ packages/protocol-identify/package.json | 3 +- packages/protocol-ping/package.json | 3 +- packages/protocol-ping/src/ping.ts | 2 ++ .../transport-circuit-relay-v2/package.json | 3 +- packages/upnp-nat/package.json | 3 +- 9 files changed, 38 insertions(+), 17 deletions(-) diff --git a/packages/protocol-autonat/package.json b/packages/protocol-autonat/package.json index 51a5c575fa..6990c2c314 100644 --- a/packages/protocol-autonat/package.json +++ b/packages/protocol-autonat/package.json @@ -58,7 +58,8 @@ "it-pipe": "^3.0.1", "private-ip": "^3.0.1", "protons-runtime": "^5.0.0", - "uint8arraylist": "^2.4.3" + "uint8arraylist": "^2.4.3", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/logger": "^3.1.0", diff --git a/packages/protocol-dcutr/package.json b/packages/protocol-dcutr/package.json index dc49dd37a4..10dbe19e8c 100644 --- a/packages/protocol-dcutr/package.json +++ b/packages/protocol-dcutr/package.json @@ -55,7 +55,8 @@ "it-protobuf-stream": "^1.0.2", "private-ip": "^3.0.1", "protons-runtime": "^5.0.0", - "uint8arraylist": "^2.4.3" + "uint8arraylist": "^2.4.3", + "yup": "^1.3.2" }, "devDependencies": { "aegir": "^41.0.2", diff --git a/packages/protocol-fetch/package.json b/packages/protocol-fetch/package.json index a85d1e07b5..99ed81c2ff 100644 --- a/packages/protocol-fetch/package.json +++ b/packages/protocol-fetch/package.json @@ -52,7 +52,8 @@ "it-protobuf-stream": "^1.0.2", "protons-runtime": "^5.0.0", "uint8arraylist": "^2.4.3", - "uint8arrays": "^4.0.6" + "uint8arrays": "^4.0.6", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/logger": "^3.1.0", diff --git a/packages/protocol-fetch/src/fetch.ts b/packages/protocol-fetch/src/fetch.ts index 4029b3f48f..eaabcf05b5 100644 --- a/packages/protocol-fetch/src/fetch.ts +++ b/packages/protocol-fetch/src/fetch.ts @@ -3,7 +3,8 @@ import { setMaxListeners } from '@libp2p/interface/events' import { pbStream } from 'it-protobuf-stream' import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' import { toString as uint8arrayToString } from 'uint8arrays/to-string' -import { PROTOCOL_NAME, PROTOCOL_VERSION } from './constants.js' +import { object, number } from 'yup' +import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, PROTOCOL_VERSION, TIMEOUT } from './constants.js' import { FetchRequest, FetchResponse } from './pb/proto.js' import type { Fetch as FetchInterface, FetchComponents, FetchInit, LookupFunction } from './index.js' import type { AbortOptions, Logger } from '@libp2p/interface' @@ -12,30 +13,41 @@ import type { PeerId } from '@libp2p/interface/peer-id' import type { Startable } from '@libp2p/interface/startable' import type { IncomingStreamData } from '@libp2p/interface-internal/registrar' -const DEFAULT_TIMEOUT = 10000 - /** * A simple libp2p protocol for requesting a value corresponding to a key from a peer. * Developers can register one or more lookup function for retrieving the value corresponding to * a given key. Each lookup function must act on a distinct part of the overall key space, defined * by a fixed prefix that all keys that should be routed to that lookup function will start with. */ + +const configValidator = object({ + timeout: number().integer().default(TIMEOUT), + maxInboundStreams: number().integer().default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().default(MAX_OUTBOUND_STREAMS) +}) export class Fetch implements Startable, FetchInterface { public readonly protocol: string private readonly components: FetchComponents private readonly lookupFunctions: Map + private readonly timeout: number + private readonly maxInboundStreams: number + private readonly maxOutboundStreams: number private started: boolean - private readonly init: FetchInit private readonly log: Logger constructor (components: FetchComponents, init: FetchInit = {}) { this.log = components.logger.forComponent('libp2p:fetch') this.started = false this.components = components - this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` this.lookupFunctions = new Map() // Maps key prefix to value lookup function this.handleMessage = this.handleMessage.bind(this) - this.init = init + + const config = configValidator.validateSync(init) + + this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.timeout = config.timeout + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams } async start (): Promise { @@ -48,8 +60,8 @@ export class Fetch implements Startable, FetchInterface { this.log.error(err) }) }, { - maxInboundStreams: this.init.maxInboundStreams, - maxOutboundStreams: this.init.maxOutboundStreams + maxInboundStreams: this.maxInboundStreams, + maxOutboundStreams: this.maxOutboundStreams }) this.started = true } @@ -76,7 +88,7 @@ export class Fetch implements Startable, FetchInterface { // create a timeout if no abort signal passed if (signal == null) { - const timeout = this.init.timeout ?? DEFAULT_TIMEOUT + const timeout = this.timeout this.log('using default timeout of %d ms', timeout) signal = AbortSignal.timeout(timeout) @@ -142,7 +154,7 @@ export class Fetch implements Startable, FetchInterface { */ async handleMessage (data: IncomingStreamData): Promise { const { stream } = data - const signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT) + const signal = AbortSignal.timeout(this.timeout) try { const pb = pbStream(stream) diff --git a/packages/protocol-identify/package.json b/packages/protocol-identify/package.json index 4e4d65344a..191a3aa924 100644 --- a/packages/protocol-identify/package.json +++ b/packages/protocol-identify/package.json @@ -58,7 +58,8 @@ "protons-runtime": "^5.0.0", "uint8arraylist": "^2.4.3", "uint8arrays": "^4.0.6", - "wherearewe": "^2.0.1" + "wherearewe": "^2.0.1", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/logger": "^3.1.0", diff --git a/packages/protocol-ping/package.json b/packages/protocol-ping/package.json index 8671c68149..1eaac15be5 100644 --- a/packages/protocol-ping/package.json +++ b/packages/protocol-ping/package.json @@ -52,7 +52,8 @@ "@multiformats/multiaddr": "^12.1.10", "it-first": "^3.0.3", "it-pipe": "^3.0.1", - "uint8arrays": "^4.0.6" + "uint8arrays": "^4.0.6", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/logger": "^3.1.0", diff --git a/packages/protocol-ping/src/ping.ts b/packages/protocol-ping/src/ping.ts index 1ffb729d70..21d615a5a6 100644 --- a/packages/protocol-ping/src/ping.ts +++ b/packages/protocol-ping/src/ping.ts @@ -43,6 +43,8 @@ export class PingService implements Startable, PingServiceInterface { this.maxInboundStreams = config.maxInboundStreams this.maxOutboundStreams = config.maxOutboundStreams this.runOnTransientConnection = config.runOnTransientConnection + + this.handleMessage = this.handleMessage.bind(this) } async start (): Promise { diff --git a/packages/transport-circuit-relay-v2/package.json b/packages/transport-circuit-relay-v2/package.json index 10d61cb983..e971a318e0 100644 --- a/packages/transport-circuit-relay-v2/package.json +++ b/packages/transport-circuit-relay-v2/package.json @@ -64,7 +64,8 @@ "p-retry": "^6.1.0", "protons-runtime": "^5.0.0", "uint8arraylist": "^2.4.3", - "uint8arrays": "^4.0.6" + "uint8arrays": "^4.0.6", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/interface-compliance-tests": "^4.1.5", diff --git a/packages/upnp-nat/package.json b/packages/upnp-nat/package.json index b9f939230c..d4d095b95c 100644 --- a/packages/upnp-nat/package.json +++ b/packages/upnp-nat/package.json @@ -51,7 +51,8 @@ "@libp2p/utils": "^4.0.7", "@multiformats/multiaddr": "^12.1.10", "private-ip": "^3.0.1", - "wherearewe": "^2.0.1" + "wherearewe": "^2.0.1", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/logger": "^3.1.0", From 6ef127183eeb37a1afc2fd1b519a760c17cb35e7 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 20 Nov 2023 22:44:23 -0500 Subject: [PATCH 08/15] chore: fix identify issue --- packages/integration-tests/.aegir.js | 4 ++-- packages/protocol-fetch/src/constants.ts | 4 ++-- packages/protocol-identify/src/consts.ts | 2 -- packages/protocol-identify/src/identify.ts | 4 +--- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/integration-tests/.aegir.js b/packages/integration-tests/.aegir.js index 6517c7b1ea..b1e634a5f7 100644 --- a/packages/integration-tests/.aegir.js +++ b/packages/integration-tests/.aegir.js @@ -22,7 +22,7 @@ export default { const peerId = await createEd25519PeerId() const libp2p = await createLibp2p({ connectionManager: { - inboundConnectionThreshold: Infinity, + inboundConnectionThreshold: 10000, minConnections: 0 }, addresses: { @@ -47,7 +47,7 @@ export default { identify: identify(), relay: circuitRelayServer({ reservations: { - maxReservations: Infinity + maxReservations: 10000 } }) } diff --git a/packages/protocol-fetch/src/constants.ts b/packages/protocol-fetch/src/constants.ts index c55751f43c..41419803ee 100644 --- a/packages/protocol-fetch/src/constants.ts +++ b/packages/protocol-fetch/src/constants.ts @@ -2,6 +2,6 @@ export const PROTOCOL_VERSION = '0.0.1' export const PROTOCOL_NAME = 'fetch' -export const MAX_INBOUND_STREAMS = 1 -export const MAX_OUTBOUND_STREAMS = 1 +export const MAX_INBOUND_STREAMS = 10 +export const MAX_OUTBOUND_STREAMS = 10 export const TIMEOUT = 10000 diff --git a/packages/protocol-identify/src/consts.ts b/packages/protocol-identify/src/consts.ts index 4c71740b45..0afb45bdf4 100644 --- a/packages/protocol-identify/src/consts.ts +++ b/packages/protocol-identify/src/consts.ts @@ -2,8 +2,6 @@ export const PROTOCOL_VERSION = 'ipfs/0.1.0' // deprecated export const MULTICODEC_IDENTIFY = '/ipfs/id/1.0.0' // deprecated export const MULTICODEC_IDENTIFY_PUSH = '/ipfs/id/push/1.0.0' // deprecated -export const AGENT_VERSION = 'js-libp2p/1.0.0' - export const PROTOCOL_PREFIX = 'ipfs' export const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8 // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52 export const MAX_INBOUND_STREAMS = 1 diff --git a/packages/protocol-identify/src/identify.ts b/packages/protocol-identify/src/identify.ts index 841328fa01..dda702e2b3 100644 --- a/packages/protocol-identify/src/identify.ts +++ b/packages/protocol-identify/src/identify.ts @@ -12,7 +12,6 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe' import { boolean, number, object, string } from 'yup' import { - AGENT_VERSION, IDENTIFY_PROTOCOL_VERSION, MULTICODEC_IDENTIFY_PROTOCOL_NAME, MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME, @@ -43,7 +42,6 @@ import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/r const configValidator = object({ protocolPrefix: string().default(PROTOCOL_PREFIX), - agentVersion: string().default(AGENT_VERSION), timeout: number().integer().min(0).default(TIMEOUT), maxIdentifyMessageSize: number().integer().min(0).default(MAX_IDENTIFY_MESSAGE_SIZE), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), @@ -108,7 +106,7 @@ export class Identify implements Startable, IdentifyInterface { // Store self host metadata this.host = { protocolVersion: `${config.protocolPrefix}/${IDENTIFY_PROTOCOL_VERSION}`, - agentVersion: config.agentVersion + agentVersion: init.agentVersion ?? `${components.nodeInfo.name}/${components.nodeInfo.version}` } if (this.runOnConnectionOpen) { From e25bdb8003dae3bf1f22fa64e28afa1decc00d1a Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 21 Nov 2023 22:36:57 -0500 Subject: [PATCH 09/15] fix: remove max parallel dials per peer param --- .../integration-tests/test/circuit-relay-discovery.node.ts | 2 -- packages/libp2p/src/connection-manager/utils.ts | 2 -- packages/protocol-fetch/src/constants.ts | 4 ++-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/integration-tests/test/circuit-relay-discovery.node.ts b/packages/integration-tests/test/circuit-relay-discovery.node.ts index 2f49fde243..41f6490e80 100644 --- a/packages/integration-tests/test/circuit-relay-discovery.node.ts +++ b/packages/integration-tests/test/circuit-relay-discovery.node.ts @@ -2,7 +2,6 @@ import { yamux } from '@chainsafe/libp2p-yamux' import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '@libp2p/circuit-relay-v2' -import { identify } from '@libp2p/identify' import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { expect } from 'aegir/chai' @@ -35,7 +34,6 @@ describe('circuit-relay discovery', () => { mockContentRouting() ], services: { - identify: identify(), relay: circuitRelayServer({ advertise: { bootDelay: 10 diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 6c3fee1aff..7a017a8113 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -78,8 +78,6 @@ export const validateConnectionManagerConfig = (opts: ConnectionManagerInit): Ob autoDialConcurrency: number().integer().min(0).default(AUTO_DIAL_CONCURRENCY), autoDialPriority: number().integer().min(0).default(AUTO_DIAL_PRIORITY), maxParallelDials: number().integer().min(0).default(MAX_PARALLEL_DIALS), - // #TODO: To be removed https://github.com/libp2p/js-libp2p/issues/2090 - maxParallelDialsPerPeer: number().max(1, 'maxParallelDialsPerPeer is being removed').default(MAX_PARALLEL_DIALS_PER_PEER), maxPeerAddrsToDialed: number().min(0).integer().default(MAX_PEER_ADDRS_TO_DIAL), dialTimeout: number().integer().min(0).default(DIAL_TIMEOUT), inboundUpgradeTimeout: number().integer().min(0).default(INBOUND_UPGRADE_TIMEOUT), diff --git a/packages/protocol-fetch/src/constants.ts b/packages/protocol-fetch/src/constants.ts index 41419803ee..c55751f43c 100644 --- a/packages/protocol-fetch/src/constants.ts +++ b/packages/protocol-fetch/src/constants.ts @@ -2,6 +2,6 @@ export const PROTOCOL_VERSION = '0.0.1' export const PROTOCOL_NAME = 'fetch' -export const MAX_INBOUND_STREAMS = 10 -export const MAX_OUTBOUND_STREAMS = 10 +export const MAX_INBOUND_STREAMS = 1 +export const MAX_OUTBOUND_STREAMS = 1 export const TIMEOUT = 10000 From cf3dd84e8bcab725da8fe923cd0ecd0b048bdbc6 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 23 Nov 2023 12:18:36 -0500 Subject: [PATCH 10/15] fix: update transport with config --- .../src/transport/transport.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/transport-circuit-relay-v2/src/transport/transport.ts b/packages/transport-circuit-relay-v2/src/transport/transport.ts index 61b511de29..3e3cd5263c 100644 --- a/packages/transport-circuit-relay-v2/src/transport/transport.ts +++ b/packages/transport-circuit-relay-v2/src/transport/transport.ts @@ -5,7 +5,8 @@ import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn' import * as mafmt from '@multiformats/mafmt' import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' -import { CIRCUIT_PROTO_CODE, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' +import { object, number } from 'yup' +import { CIRCUIT_PROTO_CODE, DEFAULT_STOP_TIMEOUT, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' import { StopMessage, HopMessage, Status } from '../pb/index.js' import { RelayDiscovery } from './discovery.js' import { createListener } from './listener.js' @@ -46,11 +47,12 @@ interface ConnectOptions { disconnectOnFailure: boolean } -const defaults = { - maxInboundStopStreams: MAX_CONNECTIONS, - maxOutboundStopStreams: MAX_CONNECTIONS, - stopTimeout: 30000 -} +const configValidator = object({ + discoverRelays: number().min(0).integer().default(0), + maxInboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + maxOutboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), + stopTimeout: number().min(0).integer().default(DEFAULT_STOP_TIMEOUT) +}) export class CircuitRelayTransport implements Transport { private readonly discovery?: RelayDiscovery @@ -71,6 +73,8 @@ export class CircuitRelayTransport implements Transport { private readonly log: Logger constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) { + const config = configValidator.validateSync(init) + this.log = components.logger.forComponent('libp2p:circuit-relay:transport') this.registrar = components.registrar this.peerStore = components.peerStore @@ -81,11 +85,11 @@ export class CircuitRelayTransport implements Transport { this.upgrader = components.upgrader this.addressManager = components.addressManager this.connectionGater = components.connectionGater - this.maxInboundStopStreams = init.maxInboundStopStreams ?? defaults.maxInboundStopStreams - this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams - this.stopTimeout = init.stopTimeout ?? defaults.stopTimeout + this.maxInboundStopStreams = config.maxInboundStopStreams + this.maxOutboundStopStreams = config.maxOutboundStopStreams + this.stopTimeout = config.stopTimeout - if (init.discoverRelays != null && init.discoverRelays > 0) { + if (config.discoverRelays > 0) { this.discovery = new RelayDiscovery(components) this.discovery.addEventListener('relay:discover', (evt) => { this.reservationStore.addRelay(evt.detail, 'discovered') From 1770c3db4f38d6ce5e64f1ec584237f31ab5c6a7 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 23 Nov 2023 14:24:18 -0500 Subject: [PATCH 11/15] feat: add config validation to perf service --- .../libp2p/src/connection-manager/utils.ts | 2 +- packages/protocol-fetch/src/fetch.ts | 4 ++-- packages/protocol-perf/package.json | 3 ++- packages/protocol-perf/src/perf-service.ts | 22 ++++++++++++++----- .../src/server/advert-service.ts | 10 ++++++++- .../src/transport/reservation-store.ts | 19 ++++++++++++---- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 7a017a8113..865e98da5f 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -3,7 +3,7 @@ import { type AbortOptions, multiaddr, type Multiaddr } from '@multiformats/mult import { type ClearableSignal, anySignal } from 'any-signal' import { type ObjectSchema, array, number, object, string } from 'yup' import { validateMultiaddr } from '../config/helpers.js' -import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_INTERVAL, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, INBOUND_UPGRADE_TIMEOUT, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PARALLEL_DIALS_PER_PEER, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js' +import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_INTERVAL, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, INBOUND_UPGRADE_TIMEOUT, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js' import type { ConnectionManagerInit } from '.' import type { LoggerOptions } from '@libp2p/interface' diff --git a/packages/protocol-fetch/src/fetch.ts b/packages/protocol-fetch/src/fetch.ts index eaabcf05b5..2afb7463d5 100644 --- a/packages/protocol-fetch/src/fetch.ts +++ b/packages/protocol-fetch/src/fetch.ts @@ -22,8 +22,8 @@ import type { IncomingStreamData } from '@libp2p/interface-internal/registrar' const configValidator = object({ timeout: number().integer().default(TIMEOUT), - maxInboundStreams: number().integer().default(MAX_INBOUND_STREAMS), - maxOutboundStreams: number().integer().default(MAX_OUTBOUND_STREAMS) + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) }) export class Fetch implements Startable, FetchInterface { public readonly protocol: string diff --git a/packages/protocol-perf/package.json b/packages/protocol-perf/package.json index 09eb779b90..0c46921ff9 100644 --- a/packages/protocol-perf/package.json +++ b/packages/protocol-perf/package.json @@ -51,7 +51,8 @@ "@libp2p/interface": "^0.1.6", "@libp2p/interface-internal": "^0.1.9", "@multiformats/multiaddr": "^12.1.10", - "it-pushable": "^3.2.3" + "it-pushable": "^3.2.3", + "yup": "^1.3.2" }, "devDependencies": { "@libp2p/interface-compliance-tests": "^4.1.5", diff --git a/packages/protocol-perf/src/perf-service.ts b/packages/protocol-perf/src/perf-service.ts index aa1d862f2f..171380ff7e 100644 --- a/packages/protocol-perf/src/perf-service.ts +++ b/packages/protocol-perf/src/perf-service.ts @@ -1,4 +1,5 @@ import { pushable } from 'it-pushable' +import { boolean, number, object, string } from 'yup' import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, RUN_ON_TRANSIENT_CONNECTION, WRITE_BLOCK_SIZE } from './constants.js' import type { PerfOptions, PerfOutput, PerfComponents, PerfInit, Perf as PerfInterface } from './index.js' import type { Logger } from '@libp2p/interface' @@ -6,6 +7,14 @@ import type { Startable } from '@libp2p/interface/startable' import type { IncomingStreamData } from '@libp2p/interface-internal/registrar' import type { Multiaddr } from '@multiformats/multiaddr' +const configValidator = object({ + maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + protocolName: string().default(PROTOCOL_NAME), + writeBlockSize: number().integer().min(1).default(WRITE_BLOCK_SIZE), + runOnTransientConnection: boolean().default(RUN_ON_TRANSIENT_CONNECTION) +}) + export class Perf implements Startable, PerfInterface { private readonly log: Logger public readonly protocol: string @@ -21,12 +30,15 @@ export class Perf implements Startable, PerfInterface { this.components = components this.log = components.logger.forComponent('libp2p:perf') this.started = false - this.protocol = init.protocolName ?? PROTOCOL_NAME - this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE + + const config = configValidator.validateSync(init) + + this.protocol = config.protocolName + this.writeBlockSize = config.writeBlockSize + this.maxInboundStreams = config.maxInboundStreams + this.maxOutboundStreams = config.maxOutboundStreams + this.runOnTransientConnection = config.runOnTransientConnection this.databuf = new ArrayBuffer(this.writeBlockSize) - this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS - this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS - this.runOnTransientConnection = init.runOnTransientConnection ?? RUN_ON_TRANSIENT_CONNECTION } async start (): Promise { diff --git a/packages/transport-circuit-relay-v2/src/server/advert-service.ts b/packages/transport-circuit-relay-v2/src/server/advert-service.ts index 80a7d9aecc..3aa6f51ae7 100644 --- a/packages/transport-circuit-relay-v2/src/server/advert-service.ts +++ b/packages/transport-circuit-relay-v2/src/server/advert-service.ts @@ -1,5 +1,6 @@ import { TypedEventEmitter } from '@libp2p/interface/events' import pRetry from 'p-retry' +import { number, object } from 'yup' import { DEFAULT_ADVERT_BOOT_DELAY, ERR_NO_ROUTERS_AVAILABLE, @@ -30,6 +31,10 @@ export interface AdvertServiceEvents { 'advert:error': CustomEvent } +const configValidator = object({ + bootDelay: number().integer().min(0).default(DEFAULT_ADVERT_BOOT_DELAY) +}) + export class AdvertService extends TypedEventEmitter implements Startable { private readonly contentRouting: ContentRouting private timeout?: any @@ -45,8 +50,11 @@ export class AdvertService extends TypedEventEmitter implem this.log = components.logger.forComponent('libp2p:circuit-relay:advert-service') this.contentRouting = components.contentRouting - this.bootDelay = init?.bootDelay ?? DEFAULT_ADVERT_BOOT_DELAY this.started = false + + const config = configValidator.validateSync(init) + + this.bootDelay = config.bootDelay } isStarted (): boolean { diff --git a/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts b/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts index f65ce3c241..392d82948e 100644 --- a/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts +++ b/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts @@ -4,6 +4,7 @@ import { PeerJobQueue } from '@libp2p/utils/peer-job-queue' import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { number, object } from 'yup' import { DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js' import { HopMessage, Status } from '../pb/index.js' import { getExpirationMilliseconds } from '../utils.js' @@ -75,6 +76,13 @@ export interface ReservationStoreEvents { 'relay:removed': CustomEvent } +const configValidator = object({ + discoverRelays: number().integer().min(0).default(0), + maxReservationQueueLength: number().integer().min(0).default(100), + reservationCompletionTimeout: number().integer().min(0).default(10000), + reservationConcurrency: number().integer().min(0).default(DEFAULT_RESERVATION_CONCURRENCY) +}) + export class ReservationStore extends TypedEventEmitter implements Startable { private readonly peerId: PeerId private readonly connectionManager: ConnectionManager @@ -99,14 +107,17 @@ export class ReservationStore extends TypedEventEmitter this.peerStore = components.peerStore this.events = components.events this.reservations = new PeerMap() - this.maxDiscoveredRelays = init?.discoverRelays ?? 0 - this.maxReservationQueueLength = init?.maxReservationQueueLength ?? 100 - this.reservationCompletionTimeout = init?.reservationCompletionTimeout ?? 10000 + + const config = configValidator.validateSync(init) + + this.maxDiscoveredRelays = config.discoverRelays + this.maxReservationQueueLength = config.maxReservationQueueLength + this.reservationCompletionTimeout = config.reservationCompletionTimeout this.started = false // ensure we don't listen on multiple relays simultaneously this.reserveQueue = new PeerJobQueue({ - concurrency: init?.reservationConcurrency ?? DEFAULT_RESERVATION_CONCURRENCY + concurrency: config.reservationConcurrency }) // When a peer disconnects, if we had a reservation on that peer From f8e3193b4830d2a522f514a037617400448d3d84 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 23 Nov 2023 23:12:36 -0500 Subject: [PATCH 12/15] fix: update config to sort addresses properly --- packages/libp2p/src/config/config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/libp2p/src/config/config.ts b/packages/libp2p/src/config/config.ts index 10045aa9f8..4f3799baf2 100644 --- a/packages/libp2p/src/config/config.ts +++ b/packages/libp2p/src/config/config.ts @@ -1,5 +1,5 @@ import { FaultTolerance } from '@libp2p/interface/transport' -import { publicAddressesFirst } from '@libp2p/utils/address-sort' +import { defaultAddressSort } from '@libp2p/utils/address-sort' import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' import mergeOptions from 'merge-options' import { object } from 'yup' @@ -15,7 +15,7 @@ const DefaultConfig: Partial = { resolvers: { dnsaddr: dnsaddrResolver }, - addressSorter: publicAddressesFirst + addressSorter: defaultAddressSort }, transportManager: { faultTolerance: FaultTolerance.FATAL_ALL From 94e19d85dca82fc46eb3c57c35b59d350352a99c Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 29 Nov 2023 14:23:42 -0500 Subject: [PATCH 13/15] fix: fixes related to PR feedback --- packages/libp2p/src/address-manager/utils.ts | 3 +-- packages/libp2p/src/config/config.ts | 7 +++---- packages/libp2p/src/config/helpers.ts | 5 +++++ packages/libp2p/src/connection-manager/utils.ts | 6 +++--- packages/protocol-dcutr/src/constants.ts | 12 ++++++++++++ packages/protocol-dcutr/src/dcutr.ts | 14 +++++--------- packages/protocol-fetch/src/constants.ts | 1 + packages/protocol-fetch/src/fetch.ts | 10 ++++++---- packages/protocol-identify/src/identify.ts | 8 ++++---- packages/protocol-ping/src/constants.ts | 1 + packages/protocol-ping/src/ping.ts | 4 ++-- .../transport-circuit-relay-v2/src/constants.ts | 8 ++++++++ .../src/server/index.ts | 16 +++------------- .../src/server/reservation-store.ts | 12 ++++++------ .../src/transport/reservation-store.ts | 8 ++++---- .../src/transport/transport.ts | 4 ++-- packages/upnp-nat/src/upnp-nat.ts | 6 ++++-- 17 files changed, 70 insertions(+), 55 deletions(-) create mode 100644 packages/protocol-dcutr/src/constants.ts diff --git a/packages/libp2p/src/address-manager/utils.ts b/packages/libp2p/src/address-manager/utils.ts index c0b53ec010..02d460bad3 100644 --- a/packages/libp2p/src/address-manager/utils.ts +++ b/packages/libp2p/src/address-manager/utils.ts @@ -1,6 +1,5 @@ import { type ObjectSchema, object, array, string, mixed } from 'yup' import { validateMultiaddr } from '../config/helpers.js' -import type { AddressManagerInit } from '.' import type { Multiaddr } from '@multiformats/multiaddr' export function debounce (func: () => void, wait: number): () => void { @@ -17,7 +16,7 @@ export function debounce (func: () => void, wait: number): () => void { } } -export function validateAddressManagerConfig (opts: AddressManagerInit): ObjectSchema> { +export function validateAddressManagerConfig (): ObjectSchema> { return object({ listen: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), announce: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), diff --git a/packages/libp2p/src/config/config.ts b/packages/libp2p/src/config/config.ts index 4f3799baf2..f761ad8410 100644 --- a/packages/libp2p/src/config/config.ts +++ b/packages/libp2p/src/config/config.ts @@ -5,12 +5,11 @@ import mergeOptions from 'merge-options' import { object } from 'yup' import { validateAddressManagerConfig } from '../address-manager/utils.js' import { validateConnectionManagerConfig } from '../connection-manager/utils.js' -import type { AddressManagerInit } from '../address-manager' import type { ConnectionManagerInit } from '../connection-manager/index.js' import type { Libp2pInit } from '../index.js' import type { ServiceMap, RecursivePartial } from '@libp2p/interface' -const DefaultConfig: Partial = { +const defaultConfig: Partial = { connectionManager: { resolvers: { dnsaddr: dnsaddrResolver @@ -24,13 +23,13 @@ const DefaultConfig: Partial = { export function validateConfig> (opts: RecursivePartial>): Libp2pInit { const libp2pConfig = object({ - addresses: validateAddressManagerConfig(opts?.addresses as AddressManagerInit), + addresses: validateAddressManagerConfig(), connectionManager: validateConnectionManagerConfig(opts?.connectionManager as ConnectionManagerInit) }) const parsedOpts = libp2pConfig.validateSync(opts) - const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, parsedOpts) + const resultingOptions: Libp2pInit = mergeOptions(defaultConfig, parsedOpts) return resultingOptions } diff --git a/packages/libp2p/src/config/helpers.ts b/packages/libp2p/src/config/helpers.ts index 0cf87f152e..fa0d99b274 100644 --- a/packages/libp2p/src/config/helpers.ts +++ b/packages/libp2p/src/config/helpers.ts @@ -3,6 +3,10 @@ import { multiaddr } from '@multiformats/multiaddr' import { codes } from '../errors.js' export const validateMultiaddr = (value: Array | undefined): boolean => { + if (value == null || value === undefined) { + return false + } + value?.forEach((addr) => { try { multiaddr(addr) @@ -10,5 +14,6 @@ export const validateMultiaddr = (value: Array | undefined): throw new CodeError(`invalid multiaddr: ${addr}`, codes.ERR_INVALID_MULTIADDR) } }) + return true } diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index bb95c73b9a..917dc3df0c 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -78,11 +78,11 @@ export const validateConnectionManagerConfig = (opts: ConnectionManagerInit): Ob autoDialConcurrency: number().integer().min(0).default(AUTO_DIAL_CONCURRENCY), autoDialPriority: number().integer().min(0).default(AUTO_DIAL_PRIORITY), maxParallelDials: number().integer().min(0).default(MAX_PARALLEL_DIALS), - maxPeerAddrsToDialed: number().min(0).integer().default(MAX_PEER_ADDRS_TO_DIAL), + maxPeerAddrsToDialed: number().integer().min(0).default(MAX_PEER_ADDRS_TO_DIAL), dialTimeout: number().integer().min(0).default(DIAL_TIMEOUT), inboundUpgradeTimeout: number().integer().min(0).default(INBOUND_UPGRADE_TIMEOUT), - allow: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), - deny: array().of(string()).test('is multiaddr', validateMultiaddr).optional(), + allow: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), + deny: array().of(string()).test('is multiaddr', validateMultiaddr).default([]), inboundConnectionThreshold: number().integer().min(0).default(INBOUND_CONNECTION_THRESHOLD), maxIncomingPendingConnections: number().integer().min(0).default(MAX_INCOMING_PENDING_CONNECTIONS) }) diff --git a/packages/protocol-dcutr/src/constants.ts b/packages/protocol-dcutr/src/constants.ts new file mode 100644 index 0000000000..e5d4debba5 --- /dev/null +++ b/packages/protocol-dcutr/src/constants.ts @@ -0,0 +1,12 @@ +// https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#rpc-messages +export const MAX_DCUTR_MESSAGE_SIZE = 1024 * 4 +// ensure the dial has a high priority to jump to the head of the dial queue +export const DCUTR_DIAL_PRIORITY = 100 + +export const DEFAULT_MAX_INBOUND_STREAMS = 1 + +export const DEFAULT_MAX_OUTBOUND_STREAMS = 1 + +export const DEFAULT_TIMEOUT = 5000 + +export const DEFAULT_RETRIES = 3 diff --git a/packages/protocol-dcutr/src/dcutr.ts b/packages/protocol-dcutr/src/dcutr.ts index 6a44a7ed02..fad6358bb0 100644 --- a/packages/protocol-dcutr/src/dcutr.ts +++ b/packages/protocol-dcutr/src/dcutr.ts @@ -3,6 +3,7 @@ import { type Multiaddr, multiaddr } from '@multiformats/multiaddr' import delay from 'delay' import { pbStream } from 'it-protobuf-stream' import { number, object } from 'yup' +import { DCUTR_DIAL_PRIORITY, DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS, DEFAULT_RETRIES, DEFAULT_TIMEOUT, MAX_DCUTR_MESSAGE_SIZE } from './constants.js' import { HolePunch } from './pb/message.js' import { isPublicAndDialable } from './utils.js' import { multicodec } from './index.js' @@ -10,18 +11,13 @@ import type { DCUtRServiceComponents, DCUtRServiceInit } from './index.js' import type { Logger, Connection, Stream, PeerStore, Startable } from '@libp2p/interface' import type { AddressManager, ConnectionManager, Registrar, TransportManager } from '@libp2p/interface-internal' -// https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#rpc-messages -const MAX_DCUTR_MESSAGE_SIZE = 1024 * 4 -// ensure the dial has a high priority to jump to the head of the dial queue -const DCUTR_DIAL_PRIORITY = 100 - const configValidator = object({ // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L27 - timeout: number().integer().default(5000).min(0), + timeout: number().integer().min(0).default(DEFAULT_TIMEOUT), // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/holepunch/holepuncher.go#L28 - retries: number().integer().default(3).min(0), - maxInboundStreams: number().integer().default(1).min(0), - maxOutboundStreams: number().integer().default(1).min(0) + retries: number().integer().min(0).default(DEFAULT_RETRIES), + maxInboundStreams: number().integer().min(0).default(DEFAULT_MAX_INBOUND_STREAMS), + maxOutboundStreams: number().integer().min(0).default(DEFAULT_MAX_OUTBOUND_STREAMS) }) export class DefaultDCUtRService implements Startable { diff --git a/packages/protocol-fetch/src/constants.ts b/packages/protocol-fetch/src/constants.ts index c55751f43c..ad6769121b 100644 --- a/packages/protocol-fetch/src/constants.ts +++ b/packages/protocol-fetch/src/constants.ts @@ -5,3 +5,4 @@ export const PROTOCOL_NAME = 'fetch' export const MAX_INBOUND_STREAMS = 1 export const MAX_OUTBOUND_STREAMS = 1 export const TIMEOUT = 10000 +export const PROTOCOL_PREFIX = 'libp2p' diff --git a/packages/protocol-fetch/src/fetch.ts b/packages/protocol-fetch/src/fetch.ts index 4eb4ca683c..f23ed8c6dc 100644 --- a/packages/protocol-fetch/src/fetch.ts +++ b/packages/protocol-fetch/src/fetch.ts @@ -2,8 +2,8 @@ import { CodeError, ERR_INVALID_MESSAGE, ERR_INVALID_PARAMETERS, ERR_TIMEOUT, se import { pbStream } from 'it-protobuf-stream' import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' import { toString as uint8arrayToString } from 'uint8arrays/to-string' -import { object, number } from 'yup' -import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, PROTOCOL_VERSION, TIMEOUT } from './constants.js' +import { object, number, string } from 'yup' +import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, PROTOCOL_PREFIX, PROTOCOL_VERSION, TIMEOUT } from './constants.js' import { FetchRequest, FetchResponse } from './pb/proto.js' import type { Fetch as FetchInterface, FetchComponents, FetchInit, LookupFunction } from './index.js' import type { AbortOptions, Logger, Stream, PeerId, Startable } from '@libp2p/interface' @@ -19,8 +19,10 @@ import type { IncomingStreamData } from '@libp2p/interface-internal' const configValidator = object({ timeout: number().integer().default(TIMEOUT), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), - maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS) + maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), + protocolPrefix: string().default(PROTOCOL_PREFIX) }) + export class Fetch implements Startable, FetchInterface { public readonly protocol: string private readonly components: FetchComponents @@ -40,7 +42,7 @@ export class Fetch implements Startable, FetchInterface { const config = configValidator.validateSync(init) - this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + this.protocol = `/${config.protocolPrefix}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` this.timeout = config.timeout this.maxInboundStreams = config.maxInboundStreams this.maxOutboundStreams = config.maxOutboundStreams diff --git a/packages/protocol-identify/src/identify.ts b/packages/protocol-identify/src/identify.ts index a3934f0641..6370031011 100644 --- a/packages/protocol-identify/src/identify.ts +++ b/packages/protocol-identify/src/identify.ts @@ -20,9 +20,9 @@ import { MAX_OUTBOUND_STREAMS, MAX_IDENTIFY_MESSAGE_SIZE, TIMEOUT, - RUN_ON_CONNECTION_OPEN, + RUN_ON_CONNECTION_OPEN as DEFAULT_RUN_ON_CONNECTION_OPEN, PROTOCOL_PREFIX, - RUN_ON_TRANSIENT_CONNECTION, + RUN_ON_TRANSIENT_CONNECTION as DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS, MAX_PUSH_INCOMING_STREAMS, MAX_PUSH_OUTGOING_STREAMS, MAX_OBSERVED_ADDRESSES @@ -41,8 +41,8 @@ const configValidator = object({ maxPushOutgoingStreams: number().integer().min(0).default(MAX_PUSH_OUTGOING_STREAMS), maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), maxObservedAddresses: number().integer().min(0).default(MAX_OBSERVED_ADDRESSES), - runOnConnectionOpen: boolean().default(RUN_ON_CONNECTION_OPEN), - runOnTransientConnection: boolean().default(RUN_ON_TRANSIENT_CONNECTION) + runOnConnectionOpen: boolean().default(DEFAULT_RUN_ON_CONNECTION_OPEN), + runOnTransientConnection: boolean().default(DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS) }) export class Identify implements Startable, IdentifyInterface { diff --git a/packages/protocol-ping/src/constants.ts b/packages/protocol-ping/src/constants.ts index 0e16b6b72b..6808799939 100644 --- a/packages/protocol-ping/src/constants.ts +++ b/packages/protocol-ping/src/constants.ts @@ -13,5 +13,6 @@ export const TIMEOUT = 10000 // opening stream A even though the dialing peer is opening stream B and closing stream A). export const MAX_INBOUND_STREAMS = 2 export const MAX_OUTBOUND_STREAMS = 1 +export const DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS = true export const ERR_WRONG_PING_ACK = 'ERR_WRONG_PING_ACK' diff --git a/packages/protocol-ping/src/ping.ts b/packages/protocol-ping/src/ping.ts index b1f69f2926..1f7a79b2fa 100644 --- a/packages/protocol-ping/src/ping.ts +++ b/packages/protocol-ping/src/ping.ts @@ -4,7 +4,7 @@ import first from 'it-first' import { pipe } from 'it-pipe' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import { boolean, number, object, string } from 'yup' -import { PROTOCOL_PREFIX, PROTOCOL_NAME, PING_LENGTH, PROTOCOL_VERSION, TIMEOUT, MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, ERR_WRONG_PING_ACK } from './constants.js' +import { PROTOCOL_PREFIX, PROTOCOL_NAME, PING_LENGTH, PROTOCOL_VERSION, TIMEOUT, MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, ERR_WRONG_PING_ACK, DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS } from './constants.js' import type { PingServiceComponents, PingServiceInit, PingService as PingServiceInterface } from './index.js' import type { AbortOptions, Logger, Stream, PeerId, Startable } from '@libp2p/interface' import type { IncomingStreamData } from '@libp2p/interface-internal' @@ -15,7 +15,7 @@ const configValidator = object({ timeout: number().integer().min(0).default(TIMEOUT), maxInboundStreams: number().integer().min(0).default(MAX_INBOUND_STREAMS), maxOutboundStreams: number().integer().min(0).default(MAX_OUTBOUND_STREAMS), - runOnTransientConnection: boolean().default(true) + runOnTransientConnection: boolean().default(DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS) }) export class PingService implements Startable, PingServiceInterface { diff --git a/packages/transport-circuit-relay-v2/src/constants.ts b/packages/transport-circuit-relay-v2/src/constants.ts index 10526ae442..7d35a7d707 100644 --- a/packages/transport-circuit-relay-v2/src/constants.ts +++ b/packages/transport-circuit-relay-v2/src/constants.ts @@ -42,6 +42,14 @@ export const RELAY_SOURCE_TAG = 'circuit-relay-source' export const RELAY_TAG = 'circuit-relay-relay' +export const DEFAULT_DEFAULT_APPLY_LIMIT = true + +export const DEFAULT_RESERVATION_COMPLETION_TIMEOUT = 10000 + +export const DEFAULT_MAX_RESERVATION_QUEUE_LENGTH = 100 + +export const DEFAULT_DISCOVER_RELAYS = 0 + // circuit v2 connection limits // https://github.com/libp2p/go-libp2p/blob/master/p2p/protocol/circuitv2/relay/resources.go#L61-L66 diff --git a/packages/transport-circuit-relay-v2/src/server/index.ts b/packages/transport-circuit-relay-v2/src/server/index.ts index 3b25e7b8d5..109a5cd71c 100644 --- a/packages/transport-circuit-relay-v2/src/server/index.ts +++ b/packages/transport-circuit-relay-v2/src/server/index.ts @@ -4,16 +4,12 @@ import { RecordEnvelope } from '@libp2p/peer-record' import { type Multiaddr, multiaddr } from '@multiformats/multiaddr' import { pbStream, type ProtobufStream } from 'it-protobuf-stream' import pDefer from 'p-defer' -import { object, number, boolean } from 'yup' +import { object, number } from 'yup' import { CIRCUIT_PROTO_CODE, - DEFAULT_DURATION_LIMIT, DEFAULT_HOP_TIMEOUT, DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS, - DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, - DEFAULT_MAX_RESERVATION_STORE_SIZE, - DEFAULT_MAX_RESERVATION_TTL, MAX_CONNECTIONS, RELAY_SOURCE_TAG, RELAY_V2_HOP_CODEC, @@ -22,7 +18,7 @@ import { import { HopMessage, type Reservation, Status, StopMessage } from '../pb/index.js' import { createLimitedRelay } from '../utils.js' import { AdvertService, type AdvertServiceComponents, type AdvertServiceInit } from './advert-service.js' -import { ReservationStore, type ReservationStoreInit } from './reservation-store.js' +import { ReservationStore, reservationStoreConfigValidator, type ReservationStoreInit } from './reservation-store.js' import { ReservationVoucherRecord } from './reservation-voucher.js' import type { CircuitRelayService, RelayReservation } from '../index.js' import type { ComponentLogger, Logger, Connection, Stream, ConnectionGater, PeerId, PeerStore, Startable } from '@libp2p/interface' @@ -95,13 +91,7 @@ export interface RelayServerEvents { const configValidator = object({ hopTimeout: number().integer().min(0).default(DEFAULT_HOP_TIMEOUT), - reservations: object({ - maxReservations: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_STORE_SIZE), - reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), - applyDefaultLimit: boolean().default(false), - reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), - defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT) - }), + reservations: reservationStoreConfigValidator, maxInboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_INBOUND_STREAMS), maxOutboundHopStreams: number().integer().min(0).default(DEFAULT_MAX_OUTBOUND_STREAMS), maxOutboundStopStreams: number().integer().min(0).default(MAX_CONNECTIONS) diff --git a/packages/transport-circuit-relay-v2/src/server/reservation-store.ts b/packages/transport-circuit-relay-v2/src/server/reservation-store.ts index 873c8a2972..293aa21bf8 100644 --- a/packages/transport-circuit-relay-v2/src/server/reservation-store.ts +++ b/packages/transport-circuit-relay-v2/src/server/reservation-store.ts @@ -1,6 +1,6 @@ import { PeerMap } from '@libp2p/peer-collections' import { object, mixed, number, boolean } from 'yup' -import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js' +import { DEFAULT_DATA_LIMIT, DEFAULT_DEFAULT_APPLY_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js' import { type Limit, Status } from '../pb/index.js' import type { RelayReservation } from '../index.js' import type { RecursivePartial, PeerId, Startable } from '@libp2p/interface' @@ -37,13 +37,13 @@ export interface ReservationStoreInit { export type ReservationStoreOptions = RecursivePartial -const configValidator = object({ +export const reservationStoreConfigValidator = object({ maxReservations: number().min(0).integer().default(DEFAULT_MAX_RESERVATION_STORE_SIZE), reservationClearInterval: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL), - applyDefaultLimit: boolean().default(true), + applyDefaultLimit: boolean().default(DEFAULT_DEFAULT_APPLY_LIMIT), reservationTtl: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_TTL), defaultDurationLimit: number().integer().min(0).default(DEFAULT_DURATION_LIMIT), - defaultDataLimit: mixed().test('is-bigint', 'Invalid bigint', value => typeof value === 'bigint').default(DEFAULT_DATA_LIMIT) + defaultDataLimit: mixed().test('is-bigint', 'Invalid bigint', value => typeof value === 'bigint').default(DEFAULT_DATA_LIMIT) }) export class ReservationStore implements Startable { public readonly reservations = new PeerMap() @@ -57,14 +57,14 @@ export class ReservationStore implements Startable { private readonly defaultDataLimit: bigint constructor (options: ReservationStoreOptions = {}) { - const config = configValidator.validateSync(options) + const config = reservationStoreConfigValidator.validateSync(options) this.maxReservations = config.maxReservations this.reservationClearInterval = config.reservationClearInterval this.applyDefaultLimit = config.applyDefaultLimit this.reservationTtl = config.reservationTtl this.defaultDurationLimit = config.defaultDurationLimit - this.defaultDataLimit = config.defaultDataLimit as bigint + this.defaultDataLimit = config.defaultDataLimit } isStarted (): boolean { diff --git a/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts b/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts index 2e56a142bf..45c83b5a29 100644 --- a/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts +++ b/packages/transport-circuit-relay-v2/src/transport/reservation-store.ts @@ -5,7 +5,7 @@ import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import { number, object } from 'yup' -import { DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js' +import { DEFAULT_DISCOVER_RELAYS, DEFAULT_MAX_RESERVATION_QUEUE_LENGTH, DEFAULT_RESERVATION_COMPLETION_TIMEOUT, DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js' import { HopMessage, Status } from '../pb/index.js' import { getExpirationMilliseconds } from '../utils.js' import type { Reservation } from '../pb/index.js' @@ -71,9 +71,9 @@ export interface ReservationStoreEvents { } const configValidator = object({ - discoverRelays: number().integer().min(0).default(0), - maxReservationQueueLength: number().integer().min(0).default(100), - reservationCompletionTimeout: number().integer().min(0).default(10000), + discoverRelays: number().integer().min(0).default(DEFAULT_DISCOVER_RELAYS), + maxReservationQueueLength: number().integer().min(0).default(DEFAULT_MAX_RESERVATION_QUEUE_LENGTH), + reservationCompletionTimeout: number().integer().min(0).default(DEFAULT_RESERVATION_COMPLETION_TIMEOUT), reservationConcurrency: number().integer().min(0).default(DEFAULT_RESERVATION_CONCURRENCY) }) diff --git a/packages/transport-circuit-relay-v2/src/transport/transport.ts b/packages/transport-circuit-relay-v2/src/transport/transport.ts index ea8698f93d..c0466dd1ac 100644 --- a/packages/transport-circuit-relay-v2/src/transport/transport.ts +++ b/packages/transport-circuit-relay-v2/src/transport/transport.ts @@ -6,7 +6,7 @@ import * as mafmt from '@multiformats/mafmt' import { multiaddr } from '@multiformats/multiaddr' import { pbStream } from 'it-protobuf-stream' import { object, number } from 'yup' -import { CIRCUIT_PROTO_CODE, DEFAULT_STOP_TIMEOUT, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' +import { CIRCUIT_PROTO_CODE, DEFAULT_DISCOVER_RELAYS, DEFAULT_STOP_TIMEOUT, ERR_HOP_REQUEST_FAILED, ERR_RELAYED_DIAL, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js' import { StopMessage, HopMessage, Status } from '../pb/index.js' import { RelayDiscovery } from './discovery.js' import { createListener } from './listener.js' @@ -40,7 +40,7 @@ interface ConnectOptions { } const configValidator = object({ - discoverRelays: number().min(0).integer().default(0), + discoverRelays: number().min(0).integer().default(DEFAULT_DISCOVER_RELAYS), maxInboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), maxOutboundStopStreams: number().min(0).integer().default(MAX_CONNECTIONS), stopTimeout: number().min(0).integer().default(DEFAULT_STOP_TIMEOUT) diff --git a/packages/upnp-nat/src/upnp-nat.ts b/packages/upnp-nat/src/upnp-nat.ts index b03cd0335c..93ba2b96b5 100644 --- a/packages/upnp-nat/src/upnp-nat.ts +++ b/packages/upnp-nat/src/upnp-nat.ts @@ -10,6 +10,8 @@ import type { Logger, Startable } from '@libp2p/interface' const DEFAULT_TTL = 7200 +const DEFAULT_KEEP_ALIVE = true + function highPort (min = 1024, max = 65535): number { return Math.floor(Math.random() * (max - min + 1) + min) } @@ -21,7 +23,7 @@ const configValidator = object({ localAddress: string().matches(validIPRegex, 'Invalid IP address'), description: string(), ttl: number().integer().min(0).default(DEFAULT_TTL), - keepAlive: boolean().default(true), + keepAlive: boolean().default(DEFAULT_KEEP_ALIVE), gateway: string().optional() }) @@ -31,7 +33,7 @@ export class UPnPNAT implements Startable { private readonly localAddress?: string private readonly description: string private readonly ttl: number - private readonly keepAlive?: boolean + private readonly keepAlive: boolean private readonly gateway?: string private started: boolean private client?: NatAPI From d1c1f25807c0622d029c333c764268986ed6cc53 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 7 Dec 2023 14:31:40 -0500 Subject: [PATCH 14/15] fix: update error + transport imports --- packages/libp2p/src/config/config.ts | 2 +- packages/libp2p/src/config/helpers.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/libp2p/src/config/config.ts b/packages/libp2p/src/config/config.ts index f761ad8410..0550e5854f 100644 --- a/packages/libp2p/src/config/config.ts +++ b/packages/libp2p/src/config/config.ts @@ -1,4 +1,4 @@ -import { FaultTolerance } from '@libp2p/interface/transport' +import { FaultTolerance } from '@libp2p/interface' import { defaultAddressSort } from '@libp2p/utils/address-sort' import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' import mergeOptions from 'merge-options' diff --git a/packages/libp2p/src/config/helpers.ts b/packages/libp2p/src/config/helpers.ts index fa0d99b274..6d6d9b310e 100644 --- a/packages/libp2p/src/config/helpers.ts +++ b/packages/libp2p/src/config/helpers.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface/errors' +import { CodeError } from '@libp2p/interface' import { multiaddr } from '@multiformats/multiaddr' import { codes } from '../errors.js' From 1eb436ef0725b64ed0b433454514dd784d7fc5f8 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 11 Jan 2024 15:43:20 -0500 Subject: [PATCH 15/15] adjust imports --- packages/libp2p/src/connection-manager/utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/libp2p/src/connection-manager/utils.ts b/packages/libp2p/src/connection-manager/utils.ts index 7519a49473..e76435edf9 100644 --- a/packages/libp2p/src/connection-manager/utils.ts +++ b/packages/libp2p/src/connection-manager/utils.ts @@ -1,8 +1,8 @@ import { type AbortOptions, multiaddr, type Multiaddr } from '@multiformats/multiaddr' import { type ObjectSchema, array, number, object, string } from 'yup' -import { validateMultiaddr } from '../config/helpers' -import { MIN_CONNECTIONS, MAX_CONNECTIONS, MAX_PARALLEL_DIALS } from './constants' -import { AUTO_DIAL_INTERVAL, AUTO_DIAL_CONCURRENCY, AUTO_DIAL_PRIORITY, MAX_PEER_ADDRS_TO_DIAL, DIAL_TIMEOUT, INBOUND_UPGRADE_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_INCOMING_PENDING_CONNECTIONS } from './constants.defaults' +import { validateMultiaddr } from '../config/helpers.js' +import { AUTO_DIAL_INTERVAL, AUTO_DIAL_CONCURRENCY, AUTO_DIAL_PRIORITY, MAX_PEER_ADDRS_TO_DIAL, DIAL_TIMEOUT, INBOUND_UPGRADE_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_INCOMING_PENDING_CONNECTIONS } from './constants.defaults.js' +import { MIN_CONNECTIONS, MAX_CONNECTIONS, MAX_PARALLEL_DIALS } from './constants.js' import type { ConnectionManagerInit } from '.' import type { LoggerOptions } from '@libp2p/interface'