diff --git a/src/circuit/client.ts b/src/circuit/client.ts index 9c2a3492e8..44401b9473 100644 --- a/src/circuit/client.ts +++ b/src/circuit/client.ts @@ -3,6 +3,7 @@ import { RELAY_V2_HOP_CODEC } from './multicodec.js' import { getExpiration, namespaceToCid } from './utils.js' import { CIRCUIT_PROTO_CODE, + DEFAULT_MAX_RESERVATIONS, RELAY_RENDEZVOUS_NS } from './constants.js' import type { PeerId } from '@libp2p/interface-peer-id' @@ -16,14 +17,25 @@ import { reserve } from './v2/index.js' import { EventEmitter, CustomEvent } from '@libp2p/interfaces/events' import type { Startable } from '@libp2p/interfaces/startable' import type { Components } from '../components.js' +import type { CircuitServiceConfig } from './index.js' const log = logger('libp2p:circuit:client') const noop = () => { } -export interface CircuitServiceInit { +/** + * CircuitServiceInit initializes the circuit service using values + * from the provided config and an @type{AddressSorter}. + */ +export interface CircuitServiceInit extends CircuitServiceConfig { + /** + * Allows prioritizing addresses from the peerstore for dialing. The + * default behavior is to prioritise public addresses. + */ addressSorter?: AddressSorter - maxReservations?: number + /** + * A callback to invoke when an error occurs in the circuit service. + */ onError?: (error: Error, msg?: string) => void } @@ -31,6 +43,10 @@ export interface CircuitServiceEvents { 'relay:reservation': CustomEvent } +/** + * CircuitService automatically makes a circuit v2 reservation on any connected + * peers that support the circuit v2 HOP protocol. + */ export class CircuitService extends EventEmitter implements Startable { private readonly components: Components private readonly addressSorter: AddressSorter @@ -45,7 +61,7 @@ export class CircuitService extends EventEmitter implement this.started = false this.components = components this.addressSorter = init.addressSorter ?? publicAddressesFirst - this.maxReservations = init.maxReservations ?? 1 + this.maxReservations = init.maxReservations ?? DEFAULT_MAX_RESERVATIONS this.relays = new Set() this.reservationMap = new Map() this.onError = init.onError ?? noop diff --git a/src/circuit/constants.ts b/src/circuit/constants.ts index b8db3b3a99..d5f301ec87 100644 --- a/src/circuit/constants.ts +++ b/src/circuit/constants.ts @@ -19,3 +19,8 @@ export const CIRCUIT_PROTO_CODE = 290 * Relay HOP relay service namespace for discovery */ export const RELAY_RENDEZVOUS_NS = '/libp2p/relay' + +/** + * Maximum reservations for auto relay + */ +export const DEFAULT_MAX_RESERVATIONS = 1 diff --git a/src/circuit/index.ts b/src/circuit/index.ts index e777e4175d..c0a41fdb66 100644 --- a/src/circuit/index.ts +++ b/src/circuit/index.ts @@ -2,21 +2,36 @@ export interface RelayConfig { enabled: boolean advertise: RelayAdvertiseConfig hop: HopConfig - autoRelay: AutoRelayConfig + service: CircuitServiceConfig } -export interface AutoRelayConfig { +/** + * CircuitServiceConfig allows the node to automatically listen + * on any discovered relays upto a specified maximum. + */ +export interface CircuitServiceConfig { + /** + * enable or disable autorelay (default: false) + */ enabled?: boolean /** - * maximum number of relays to listen + * maximum number of relays to listen (default: 1) */ - maxListeners: number + maxReservations?: number } +/** + * Configures using the node as a HOP relay + */ export interface HopConfig { + /** + * + */ enabled?: boolean - active?: boolean + /** + * timeout for hop requests to complete + */ timeout: number } diff --git a/src/circuit/relay.ts b/src/circuit/relay.ts index 2a6e6ea595..a2c5cc1bf8 100644 --- a/src/circuit/relay.ts +++ b/src/circuit/relay.ts @@ -12,20 +12,10 @@ import { import type { AddressSorter } from '@libp2p/interface-peer-store' import type { Startable } from '@libp2p/interfaces/startable' import type { Components } from '../components.js' +import type { HopConfig, RelayAdvertiseConfig } from './index.js' const log = logger('libp2p:circuit:relay') -export interface RelayAdvertiseConfig { - bootDelay?: number - enabled?: boolean - ttl?: number -} - -export interface HopConfig { - enabled?: boolean - active?: boolean -} - export interface RelayInit { addressSorter?: AddressSorter maxListeners?: number @@ -58,8 +48,8 @@ export class Relay implements Startable { * Start Relay service */ async start () { - // Advertise service if HOP enabled - if (this.init.hop.enabled !== false && this.init.advertise.enabled !== false) { + // Advertise service if HOP enabled and advertising enabled + if (this.init.hop.enabled === true && this.init.advertise.enabled === true) { this.timeout = setDelayedInterval( this._advertiseService, this.init.advertise.ttl, this.init.advertise.bootDelay ) diff --git a/src/circuit/transport.ts b/src/circuit/transport.ts index ec3a200af5..46c8589bf5 100644 --- a/src/circuit/transport.ts +++ b/src/circuit/transport.ts @@ -89,14 +89,17 @@ export class Circuit implements Transport, Startable { log.error(err) }) - await this.components.registrar.handle(RELAY_V2_HOP_CODEC, (data) => { - void this._onV2ProtocolHop(data).catch(err => { - log.error(err) - }) - }) - .catch(err => { - log.error(err) + if (this._init.hop.enabled === true) { + await this.components.registrar.handle(RELAY_V2_HOP_CODEC, (data) => { + void this._onV2ProtocolHop(data).catch(err => { + log.error(err) + }) }) + .catch(err => { + log.error(err) + }) + } + await this.components.registrar.handle(RELAY_V2_STOP_CODEC, (data) => { void this._onV2ProtocolStop(data).catch(err => { log.error(err) @@ -105,6 +108,7 @@ export class Circuit implements Transport, Startable { .catch(err => { log.error(err) }) + this.reservationStore.start() } @@ -116,11 +120,11 @@ export class Circuit implements Transport, Startable { } hopEnabled () { - return true + return this._init.hop.enabled ?? false } hopActive () { - return true + return this._init.hop.enabled ?? false } get [symbol] (): true { diff --git a/src/config.ts b/src/config.ts index e856061c99..7bc14f8f1e 100644 --- a/src/config.ts +++ b/src/config.ts @@ -58,12 +58,11 @@ const DefaultConfig: Partial = { }, hop: { enabled: false, - active: false, timeout: 30000 }, - autoRelay: { + service: { enabled: false, - maxListeners: 2 + maxReservations: 2 } }, identify: { diff --git a/src/libp2p.ts b/src/libp2p.ts index b74bc6359c..e554de4a5d 100644 --- a/src/libp2p.ts +++ b/src/libp2p.ts @@ -180,10 +180,10 @@ export class Libp2pNode extends EventEmitter implements Libp2p { }) this.configureComponent(this.identifyService) - if (init.relay.autoRelay.enabled === true) { + if (init.relay.service.enabled === true) { this.circuitService = new CircuitService(this.components, { addressSorter: init.connectionManager.addressSorter, - ...init.relay.autoRelay + ...init.relay.service }) this.services.push(this.circuitService) } diff --git a/test/circuit/v2/hop.spec.ts b/test/circuit/v2/hop.spec.ts index f9ba2c584c..df0059d6f7 100644 --- a/test/circuit/v2/hop.spec.ts +++ b/test/circuit/v2/hop.spec.ts @@ -187,12 +187,11 @@ describe('Circuit v2 - hop protocol', function () { }, hop: { enabled: true, - active: false, timeout: 30000 }, - autoRelay: { + service: { enabled: false, - maxListeners: 2 + maxReservations: 2 } }) }) diff --git a/test/dialing/resolver.spec.ts b/test/dialing/resolver.spec.ts index 52cb04944c..ce8d14a43a 100644 --- a/test/dialing/resolver.spec.ts +++ b/test/dialing/resolver.spec.ts @@ -56,7 +56,7 @@ describe('Dialing (resolvable addresses)', () => { }, relay: { enabled: true, - autoRelay: { + service: { enabled: true }, hop: { @@ -79,7 +79,7 @@ describe('Dialing (resolvable addresses)', () => { }, relay: { enabled: true, - autoRelay: { + service: { enabled: true }, hop: { diff --git a/test/relay/auto-relay.node.ts b/test/relay/auto-relay.node.ts index 094f26df15..e6bcda5606 100644 --- a/test/relay/auto-relay.node.ts +++ b/test/relay/auto-relay.node.ts @@ -364,9 +364,9 @@ describe('auto-relay', () => { ttl: 1000, enabled: true }, - autoRelay: { + service: { enabled: true, - maxListeners: 1 + maxReservations: 1 } }, contentRouters: [ diff --git a/test/relay/relay.node.ts b/test/relay/relay.node.ts index fe8aef7c46..fd86b72eeb 100644 --- a/test/relay/relay.node.ts +++ b/test/relay/relay.node.ts @@ -5,9 +5,6 @@ import { pEvent } from 'p-event' import * as sinon from 'sinon' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { RELAY_V2_HOP_CODEC } from '../../src/circuit/multicodec.js' -import { CircuitRelay } from '../../src/circuit/v1/pb/index.js' -import { HopMessage } from '../../src/circuit/v2/pb/index.js' -import { StreamHandlerV2 } from '../../src/circuit/v2/stream-handler.js' import { codes as Errors } from '../../src/errors.js' import type { Libp2pNode } from '../../src/libp2p.js' import { createNode } from '../utils/creators/peer.js' @@ -28,7 +25,7 @@ describe('Dialing (via relay, TCP)', () => { createNode({ config: createNodeOptions({ relay: { - autoRelay: { + service: { enabled: false } } @@ -37,7 +34,7 @@ describe('Dialing (via relay, TCP)', () => { createNode({ config: createRelayOptions({ relay: { - autoRelay: { + service: { enabled: false } } @@ -46,7 +43,7 @@ describe('Dialing (via relay, TCP)', () => { createNode({ config: createNodeOptions({ relay: { - autoRelay: { + service: { enabled: true } } @@ -162,14 +159,11 @@ describe('Dialing (via relay, TCP)', () => { // send an invalid relay message from the relay to the destination peer const connections = relayLibp2p.getConnections(dstLibp2p.peerId) - const stream = await connections[0].newStream(RELAY_V2_HOP_CODEC) - const streamHandler = new StreamHandlerV2({ stream }) + // this should fail as the destination peer has HOP disabled + await expect(connections[0].newStream(RELAY_V2_HOP_CODEC)) + .to.be.rejected() // empty messages are encoded as { type: RESERVE } for the hop codec, // so we make the message invalid by adding a zeroed byte - streamHandler.write(new Uint8Array([0])) - const res = HopMessage.decode(await streamHandler.read()) - expect(res?.status).to.equal(CircuitRelay.Status.MALFORMED_MESSAGE) - streamHandler.close() // should still be connected const dstToRelayConn = dstLibp2p.components.connectionManager.getConnections(relayLibp2p.peerId) diff --git a/test/relay/utils.ts b/test/relay/utils.ts index 3e78f26c06..2a1b7efa90 100644 --- a/test/relay/utils.ts +++ b/test/relay/utils.ts @@ -15,9 +15,9 @@ export function createNodeOptions (...overrides: Libp2pOptions[]): Libp2pOptions hop: { enabled: false }, - autoRelay: { + service: { enabled: true, - maxListeners: 1 + maxReservations: 1 } } }, ...overrides)