From a4e8aab124bdc7de7bdd3a3be5181370cb0841b7 Mon Sep 17 00:00:00 2001 From: Sasha Date: Tue, 23 Jul 2024 15:47:42 +0200 Subject: [PATCH] move relay functionality to separate package --- package.json | 2 +- packages/interfaces/src/waku.ts | 7 - packages/relay/package.json | 2 + packages/relay/src/create.ts | 40 +++ packages/relay/src/index.ts | 319 +----------------- packages/relay/src/relay.ts | 317 +++++++++++++++++ packages/sdk/package.json | 6 - packages/sdk/src/create/index.ts | 2 +- packages/sdk/src/create/libp2p.ts | 13 - packages/sdk/src/index.ts | 7 +- packages/sdk/src/relay-node/index.ts | 55 --- packages/sdk/src/waku.ts | 14 +- packages/tests/package.json | 1 + packages/tests/src/lib/runNodes.ts | 2 +- .../connection_state.spec.ts | 2 +- packages/tests/tests/enr.node.spec.ts | 2 +- .../tests/tests/relay/interop.node.spec.ts | 2 +- .../tests/relay/multiple_pubsub.node.spec.ts | 2 +- .../tests/tests/relay/subscribe.node.spec.ts | 2 +- packages/tests/tests/relay/utils.ts | 2 +- packages/tests/tests/store/utils.ts | 3 +- .../tests/wait_for_remote_peer.node.spec.ts | 2 +- packages/tests/tests/waku.node.spec.ts | 2 +- 23 files changed, 384 insertions(+), 422 deletions(-) create mode 100644 packages/relay/src/create.ts create mode 100644 packages/relay/src/relay.ts delete mode 100644 packages/sdk/src/relay-node/index.ts diff --git a/package.json b/package.json index 9c61e50df1..c06490b250 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,10 @@ "packages/message-hash", "packages/enr", "packages/core", - "packages/relay", "packages/discovery", "packages/message-encryption", "packages/sdk", + "packages/relay", "packages/tests", "packages/browser-tests", "packages/build-utils", diff --git a/packages/interfaces/src/waku.ts b/packages/interfaces/src/waku.ts index 5b54b0080a..ce1a5a6340 100644 --- a/packages/interfaces/src/waku.ts +++ b/packages/interfaces/src/waku.ts @@ -42,10 +42,3 @@ export interface RelayNode extends Waku { filter: undefined; lightPush: undefined; } - -export interface FullNode extends Waku { - relay: IRelay; - store: IStoreSDK; - filter: IFilterSDK; - lightPush: ILightPushSDK; -} diff --git a/packages/relay/package.json b/packages/relay/package.json index 858ae88075..1f5a5ff8e6 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -52,6 +52,7 @@ "@chainsafe/libp2p-gossipsub": "^12.0.0", "@noble/hashes": "^1.3.2", "@waku/core": "0.0.30", + "@waku/sdk": "0.0.26", "@waku/interfaces": "0.0.25", "@waku/proto": "0.0.7", "@waku/utils": "0.0.18", @@ -67,6 +68,7 @@ "rollup": "^4.12.0" }, "peerDependencies": { + "@waku/sdk": "0.0.26", "@waku/core": "0.0.30", "@waku/interfaces": "0.0.25", "@waku/proto": "0.0.7", diff --git a/packages/relay/src/create.ts b/packages/relay/src/create.ts new file mode 100644 index 0000000000..da8972f77b --- /dev/null +++ b/packages/relay/src/create.ts @@ -0,0 +1,40 @@ +import { type RelayNode } from "@waku/interfaces"; +import { + createLibp2pAndUpdateOptions, + CreateWakuNodeOptions, + WakuNode, + WakuOptions +} from "@waku/sdk"; + +import { RelayCreateOptions, wakuGossipSub, wakuRelay } from "./relay.js"; + +/** + * Create a Waku node that uses Waku Relay to send and receive messages, + * enabling some privacy preserving properties. + * * @remarks + * This function creates a Relay Node using the Waku Relay protocol. + * While it is technically possible to use this function in a browser environment, + * it is not recommended due to potential performance issues and limited browser capabilities. + * If you are developing a browser-based application, consider alternative approaches like creating a Light Node + * or use this function with caution. + */ +export async function createRelayNode( + options: CreateWakuNodeOptions & Partial = { + pubsubTopics: [] + } +): Promise { + options = { + ...options, + libp2p: { + ...options.libp2p, + services: { + pubsub: wakuGossipSub(options) + } + } + }; + + const libp2p = await createLibp2pAndUpdateOptions(options); + const relay = wakuRelay(options?.pubsubTopics || [])(libp2p); + + return new WakuNode(options as WakuOptions, libp2p, {}, relay) as RelayNode; +} diff --git a/packages/relay/src/index.ts b/packages/relay/src/index.ts index 831ef4c3c5..be614733b9 100644 --- a/packages/relay/src/index.ts +++ b/packages/relay/src/index.ts @@ -1,317 +1,2 @@ -import { - GossipSub, - GossipSubComponents, - GossipsubMessage, - GossipsubOpts -} from "@chainsafe/libp2p-gossipsub"; -import type { PeerIdStr, TopicStr } from "@chainsafe/libp2p-gossipsub/types"; -import { SignaturePolicy } from "@chainsafe/libp2p-gossipsub/types"; -import type { PubSub as Libp2pPubsub, PeerId } from "@libp2p/interface"; -import { sha256 } from "@noble/hashes/sha256"; -import { - ActiveSubscriptions, - Callback, - DefaultPubsubTopic, - IAsyncIterator, - IDecodedMessage, - IDecoder, - IEncoder, - IMessage, - IRelay, - Libp2p, - ProtocolCreateOptions, - ProtocolError, - PubsubTopic, - SDKProtocolResult -} from "@waku/interfaces"; -import { isWireSizeUnderCap, toAsyncIterator } from "@waku/utils"; -import { pushOrInitMapSet } from "@waku/utils"; -import { Logger } from "@waku/utils"; - -import { RelayCodecs } from "./constants.js"; -import { messageValidator } from "./message_validator.js"; -import { TopicOnlyDecoder } from "./topic_only_message.js"; - -const log = new Logger("relay"); - -export type Observer = { - decoder: IDecoder; - callback: Callback; -}; - -export type RelayCreateOptions = ProtocolCreateOptions & GossipsubOpts; -export type ContentTopic = string; - -/** - * Implements the [Waku v2 Relay protocol](https://rfc.vac.dev/spec/11/). - * Throws if libp2p.pubsub does not support Waku Relay - */ -class Relay implements IRelay { - public readonly pubsubTopics: Set; - private defaultDecoder: IDecoder; - - public static multicodec: string = RelayCodecs[0]; - public readonly gossipSub: GossipSub; - - /** - * observers called when receiving new message. - * Observers under key `""` are always called. - */ - private observers: Map>>; - - public constructor(libp2p: Libp2p, pubsubTopics: PubsubTopic[]) { - if (!this.isRelayPubsub(libp2p.services.pubsub)) { - throw Error( - `Failed to initialize Relay. libp2p.pubsub does not support ${Relay.multicodec}` - ); - } - - this.gossipSub = libp2p.services.pubsub as GossipSub; - this.pubsubTopics = new Set(pubsubTopics); - - if (this.gossipSub.isStarted()) { - this.subscribeToAllTopics(); - } - - this.observers = new Map(); - - // Default PubsubTopic decoder - // TODO: User might want to decide what decoder should be used (e.g. for RLN) - this.defaultDecoder = new TopicOnlyDecoder(); - } - - /** - * Mounts the gossipsub protocol onto the libp2p node - * and subscribes to all the topics. - * - * @override - * @returns {void} - */ - public async start(): Promise { - if (this.gossipSub.isStarted()) { - throw Error("GossipSub already started."); - } - - await this.gossipSub.start(); - this.subscribeToAllTopics(); - } - - /** - * Send Waku message. - */ - public async send( - encoder: IEncoder, - message: IMessage - ): Promise { - const successes: PeerId[] = []; - - const { pubsubTopic } = encoder; - if (!this.pubsubTopics.has(pubsubTopic)) { - log.error("Failed to send waku relay: topic not configured"); - return { - successes, - failures: [ - { - error: ProtocolError.TOPIC_NOT_CONFIGURED - } - ] - }; - } - - const msg = await encoder.toWire(message); - if (!msg) { - log.error("Failed to encode message, aborting publish"); - return { - successes, - failures: [ - { - error: ProtocolError.ENCODE_FAILED - } - ] - }; - } - - if (!isWireSizeUnderCap(msg)) { - log.error("Failed to send waku relay: message is bigger that 1MB"); - return { - successes, - failures: [ - { - error: ProtocolError.SIZE_TOO_BIG - } - ] - }; - } - - const { recipients } = await this.gossipSub.publish(pubsubTopic, msg); - return { - successes: recipients, - failures: [] - }; - } - - public subscribe( - decoders: IDecoder | IDecoder[], - callback: Callback - ): () => void { - const observers: Array<[PubsubTopic, Observer]> = []; - - for (const decoder of Array.isArray(decoders) ? decoders : [decoders]) { - const { pubsubTopic } = decoder; - const ctObs: Map>> = this.observers.get( - pubsubTopic - ) ?? new Map(); - const observer = { pubsubTopic, decoder, callback }; - pushOrInitMapSet(ctObs, decoder.contentTopic, observer); - - this.observers.set(pubsubTopic, ctObs); - observers.push([pubsubTopic, observer]); - } - - return () => { - this.removeObservers(observers); - }; - } - - private removeObservers( - observers: Array<[PubsubTopic, Observer]> - ): void { - for (const [pubsubTopic, observer] of observers) { - const ctObs = this.observers.get(pubsubTopic); - if (!ctObs) continue; - - const contentTopic = observer.decoder.contentTopic; - const _obs = ctObs.get(contentTopic); - if (!_obs) continue; - - _obs.delete(observer); - ctObs.set(contentTopic, _obs); - this.observers.set(pubsubTopic, ctObs); - } - } - - public toSubscriptionIterator( - decoders: IDecoder | IDecoder[] - ): Promise> { - return toAsyncIterator(this, decoders); - } - - public getActiveSubscriptions(): ActiveSubscriptions { - const map = new Map(); - for (const pubsubTopic of this.pubsubTopics) { - map.set(pubsubTopic, Array.from(this.observers.keys())); - } - return map; - } - - public getMeshPeers(topic: TopicStr = DefaultPubsubTopic): PeerIdStr[] { - return this.gossipSub.getMeshPeers(topic); - } - - private subscribeToAllTopics(): void { - for (const pubsubTopic of this.pubsubTopics) { - this.gossipSubSubscribe(pubsubTopic); - } - } - - private async processIncomingMessage( - pubsubTopic: string, - bytes: Uint8Array - ): Promise { - const topicOnlyMsg = await this.defaultDecoder.fromWireToProtoObj(bytes); - if (!topicOnlyMsg || !topicOnlyMsg.contentTopic) { - log.warn("Message does not have a content topic, skipping"); - return; - } - - // Retrieve the map of content topics for the given pubsubTopic - const contentTopicMap = this.observers.get(pubsubTopic); - if (!contentTopicMap) { - return; - } - - // Retrieve the set of observers for the given contentTopic - const observers = contentTopicMap.get(topicOnlyMsg.contentTopic) as Set< - Observer - >; - if (!observers) { - return; - } - - await Promise.all( - Array.from(observers).map(({ decoder, callback }) => { - return (async () => { - try { - const protoMsg = await decoder.fromWireToProtoObj(bytes); - if (!protoMsg) { - log.error( - "Internal error: message previously decoded failed on 2nd pass." - ); - return; - } - const msg = await decoder.fromProtoObj(pubsubTopic, protoMsg); - if (msg) { - await callback(msg); - } else { - log.error( - "Failed to decode messages on", - topicOnlyMsg.contentTopic - ); - } - } catch (error) { - log.error("Error while decoding message:", error); - } - })(); - }) - ); - } - - /** - * Subscribe to a pubsub topic and start emitting Waku messages to observers. - * - * @override - */ - private gossipSubSubscribe(pubsubTopic: string): void { - this.gossipSub.addEventListener( - "gossipsub:message", - (event: CustomEvent) => { - if (event.detail.msg.topic !== pubsubTopic) return; - - this.processIncomingMessage( - event.detail.msg.topic, - event.detail.msg.data - ).catch((e) => log.error("Failed to process incoming message", e)); - } - ); - - this.gossipSub.topicValidators.set(pubsubTopic, messageValidator); - this.gossipSub.subscribe(pubsubTopic); - } - - private isRelayPubsub(pubsub: Libp2pPubsub | undefined): boolean { - return pubsub?.multicodecs?.includes(Relay.multicodec) ?? false; - } -} - -export function wakuRelay( - pubsubTopics: PubsubTopic[] -): (libp2p: Libp2p) => IRelay { - return (libp2p: Libp2p) => new Relay(libp2p, pubsubTopics); -} - -export function wakuGossipSub( - init: Partial = {} -): (components: GossipSubComponents) => GossipSub { - return (components: GossipSubComponents) => { - init = { - ...init, - msgIdFn: ({ data }) => sha256(data), - // Ensure that no signature is included nor expected in the messages. - globalSignaturePolicy: SignaturePolicy.StrictNoSign, - fallbackToFloodsub: false - }; - const pubsub = new GossipSub(components, init); - pubsub.multicodecs = RelayCodecs; - return pubsub; - }; -} +export * from "./relay.js"; +export * from "./create.js"; diff --git a/packages/relay/src/relay.ts b/packages/relay/src/relay.ts new file mode 100644 index 0000000000..831ef4c3c5 --- /dev/null +++ b/packages/relay/src/relay.ts @@ -0,0 +1,317 @@ +import { + GossipSub, + GossipSubComponents, + GossipsubMessage, + GossipsubOpts +} from "@chainsafe/libp2p-gossipsub"; +import type { PeerIdStr, TopicStr } from "@chainsafe/libp2p-gossipsub/types"; +import { SignaturePolicy } from "@chainsafe/libp2p-gossipsub/types"; +import type { PubSub as Libp2pPubsub, PeerId } from "@libp2p/interface"; +import { sha256 } from "@noble/hashes/sha256"; +import { + ActiveSubscriptions, + Callback, + DefaultPubsubTopic, + IAsyncIterator, + IDecodedMessage, + IDecoder, + IEncoder, + IMessage, + IRelay, + Libp2p, + ProtocolCreateOptions, + ProtocolError, + PubsubTopic, + SDKProtocolResult +} from "@waku/interfaces"; +import { isWireSizeUnderCap, toAsyncIterator } from "@waku/utils"; +import { pushOrInitMapSet } from "@waku/utils"; +import { Logger } from "@waku/utils"; + +import { RelayCodecs } from "./constants.js"; +import { messageValidator } from "./message_validator.js"; +import { TopicOnlyDecoder } from "./topic_only_message.js"; + +const log = new Logger("relay"); + +export type Observer = { + decoder: IDecoder; + callback: Callback; +}; + +export type RelayCreateOptions = ProtocolCreateOptions & GossipsubOpts; +export type ContentTopic = string; + +/** + * Implements the [Waku v2 Relay protocol](https://rfc.vac.dev/spec/11/). + * Throws if libp2p.pubsub does not support Waku Relay + */ +class Relay implements IRelay { + public readonly pubsubTopics: Set; + private defaultDecoder: IDecoder; + + public static multicodec: string = RelayCodecs[0]; + public readonly gossipSub: GossipSub; + + /** + * observers called when receiving new message. + * Observers under key `""` are always called. + */ + private observers: Map>>; + + public constructor(libp2p: Libp2p, pubsubTopics: PubsubTopic[]) { + if (!this.isRelayPubsub(libp2p.services.pubsub)) { + throw Error( + `Failed to initialize Relay. libp2p.pubsub does not support ${Relay.multicodec}` + ); + } + + this.gossipSub = libp2p.services.pubsub as GossipSub; + this.pubsubTopics = new Set(pubsubTopics); + + if (this.gossipSub.isStarted()) { + this.subscribeToAllTopics(); + } + + this.observers = new Map(); + + // Default PubsubTopic decoder + // TODO: User might want to decide what decoder should be used (e.g. for RLN) + this.defaultDecoder = new TopicOnlyDecoder(); + } + + /** + * Mounts the gossipsub protocol onto the libp2p node + * and subscribes to all the topics. + * + * @override + * @returns {void} + */ + public async start(): Promise { + if (this.gossipSub.isStarted()) { + throw Error("GossipSub already started."); + } + + await this.gossipSub.start(); + this.subscribeToAllTopics(); + } + + /** + * Send Waku message. + */ + public async send( + encoder: IEncoder, + message: IMessage + ): Promise { + const successes: PeerId[] = []; + + const { pubsubTopic } = encoder; + if (!this.pubsubTopics.has(pubsubTopic)) { + log.error("Failed to send waku relay: topic not configured"); + return { + successes, + failures: [ + { + error: ProtocolError.TOPIC_NOT_CONFIGURED + } + ] + }; + } + + const msg = await encoder.toWire(message); + if (!msg) { + log.error("Failed to encode message, aborting publish"); + return { + successes, + failures: [ + { + error: ProtocolError.ENCODE_FAILED + } + ] + }; + } + + if (!isWireSizeUnderCap(msg)) { + log.error("Failed to send waku relay: message is bigger that 1MB"); + return { + successes, + failures: [ + { + error: ProtocolError.SIZE_TOO_BIG + } + ] + }; + } + + const { recipients } = await this.gossipSub.publish(pubsubTopic, msg); + return { + successes: recipients, + failures: [] + }; + } + + public subscribe( + decoders: IDecoder | IDecoder[], + callback: Callback + ): () => void { + const observers: Array<[PubsubTopic, Observer]> = []; + + for (const decoder of Array.isArray(decoders) ? decoders : [decoders]) { + const { pubsubTopic } = decoder; + const ctObs: Map>> = this.observers.get( + pubsubTopic + ) ?? new Map(); + const observer = { pubsubTopic, decoder, callback }; + pushOrInitMapSet(ctObs, decoder.contentTopic, observer); + + this.observers.set(pubsubTopic, ctObs); + observers.push([pubsubTopic, observer]); + } + + return () => { + this.removeObservers(observers); + }; + } + + private removeObservers( + observers: Array<[PubsubTopic, Observer]> + ): void { + for (const [pubsubTopic, observer] of observers) { + const ctObs = this.observers.get(pubsubTopic); + if (!ctObs) continue; + + const contentTopic = observer.decoder.contentTopic; + const _obs = ctObs.get(contentTopic); + if (!_obs) continue; + + _obs.delete(observer); + ctObs.set(contentTopic, _obs); + this.observers.set(pubsubTopic, ctObs); + } + } + + public toSubscriptionIterator( + decoders: IDecoder | IDecoder[] + ): Promise> { + return toAsyncIterator(this, decoders); + } + + public getActiveSubscriptions(): ActiveSubscriptions { + const map = new Map(); + for (const pubsubTopic of this.pubsubTopics) { + map.set(pubsubTopic, Array.from(this.observers.keys())); + } + return map; + } + + public getMeshPeers(topic: TopicStr = DefaultPubsubTopic): PeerIdStr[] { + return this.gossipSub.getMeshPeers(topic); + } + + private subscribeToAllTopics(): void { + for (const pubsubTopic of this.pubsubTopics) { + this.gossipSubSubscribe(pubsubTopic); + } + } + + private async processIncomingMessage( + pubsubTopic: string, + bytes: Uint8Array + ): Promise { + const topicOnlyMsg = await this.defaultDecoder.fromWireToProtoObj(bytes); + if (!topicOnlyMsg || !topicOnlyMsg.contentTopic) { + log.warn("Message does not have a content topic, skipping"); + return; + } + + // Retrieve the map of content topics for the given pubsubTopic + const contentTopicMap = this.observers.get(pubsubTopic); + if (!contentTopicMap) { + return; + } + + // Retrieve the set of observers for the given contentTopic + const observers = contentTopicMap.get(topicOnlyMsg.contentTopic) as Set< + Observer + >; + if (!observers) { + return; + } + + await Promise.all( + Array.from(observers).map(({ decoder, callback }) => { + return (async () => { + try { + const protoMsg = await decoder.fromWireToProtoObj(bytes); + if (!protoMsg) { + log.error( + "Internal error: message previously decoded failed on 2nd pass." + ); + return; + } + const msg = await decoder.fromProtoObj(pubsubTopic, protoMsg); + if (msg) { + await callback(msg); + } else { + log.error( + "Failed to decode messages on", + topicOnlyMsg.contentTopic + ); + } + } catch (error) { + log.error("Error while decoding message:", error); + } + })(); + }) + ); + } + + /** + * Subscribe to a pubsub topic and start emitting Waku messages to observers. + * + * @override + */ + private gossipSubSubscribe(pubsubTopic: string): void { + this.gossipSub.addEventListener( + "gossipsub:message", + (event: CustomEvent) => { + if (event.detail.msg.topic !== pubsubTopic) return; + + this.processIncomingMessage( + event.detail.msg.topic, + event.detail.msg.data + ).catch((e) => log.error("Failed to process incoming message", e)); + } + ); + + this.gossipSub.topicValidators.set(pubsubTopic, messageValidator); + this.gossipSub.subscribe(pubsubTopic); + } + + private isRelayPubsub(pubsub: Libp2pPubsub | undefined): boolean { + return pubsub?.multicodecs?.includes(Relay.multicodec) ?? false; + } +} + +export function wakuRelay( + pubsubTopics: PubsubTopic[] +): (libp2p: Libp2p) => IRelay { + return (libp2p: Libp2p) => new Relay(libp2p, pubsubTopics); +} + +export function wakuGossipSub( + init: Partial = {} +): (components: GossipSubComponents) => GossipSub { + return (components: GossipSubComponents) => { + init = { + ...init, + msgIdFn: ({ data }) => sha256(data), + // Ensure that no signature is included nor expected in the messages. + globalSignaturePolicy: SignaturePolicy.StrictNoSign, + fallbackToFloodsub: false + }; + const pubsub = new GossipSub(components, init); + pubsub.multicodecs = RelayCodecs; + return pubsub; + }; +} diff --git a/packages/sdk/package.json b/packages/sdk/package.json index f9ef240c36..9ee4bb2b69 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -8,10 +8,6 @@ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" - }, - "./relay": { - "types": "./dist/relay-node/index.d.ts", - "import": "./dist/relay-node/index.js" } }, "typesVersions": { @@ -72,7 +68,6 @@ "@waku/discovery": "0.0.3", "@waku/interfaces": "0.0.25", "@waku/proto": "^0.0.7", - "@waku/relay": "0.0.13", "@waku/utils": "0.0.18", "libp2p": "^1.1.2" }, @@ -93,7 +88,6 @@ "@waku/core": "0.0.30", "@waku/interfaces": "0.0.25", "@waku/message-hash": "^0.1.14", - "@waku/relay": "0.0.13", "@waku/utils": "0.0.18" }, "peerDependenciesMeta": { diff --git a/packages/sdk/src/create/index.ts b/packages/sdk/src/create/index.ts index ea0315451a..3c4d7ef825 100644 --- a/packages/sdk/src/create/index.ts +++ b/packages/sdk/src/create/index.ts @@ -1,2 +1,2 @@ export { createLightNode } from "./create.js"; -export { defaultLibp2p } from "./libp2p.js"; +export { defaultLibp2p, createLibp2pAndUpdateOptions } from "./libp2p.js"; diff --git a/packages/sdk/src/create/libp2p.ts b/packages/sdk/src/create/libp2p.ts index 4307e33d53..435a4c136b 100644 --- a/packages/sdk/src/create/libp2p.ts +++ b/packages/sdk/src/create/libp2p.ts @@ -1,4 +1,3 @@ -import type { GossipSub } from "@chainsafe/libp2p-gossipsub"; import { noise } from "@chainsafe/libp2p-noise"; import { bootstrap } from "@libp2p/bootstrap"; import { identify } from "@libp2p/identify"; @@ -15,7 +14,6 @@ import { type Libp2pComponents, type ShardInfo } from "@waku/interfaces"; -import { wakuGossipSub } from "@waku/relay"; import { ensureShardingConfigured, Logger } from "@waku/utils"; import { createLibp2p } from "libp2p"; @@ -27,10 +25,6 @@ import { import { defaultPeerDiscoveries } from "./discovery.js"; -type PubsubService = { - pubsub?: (components: Libp2pComponents) => GossipSub; -}; - type MetadataService = { metadata?: (components: Libp2pComponents) => IMetadata; }; @@ -39,7 +33,6 @@ const logger = new Logger("sdk:create"); export async function defaultLibp2p( shardInfo?: ShardInfo, - wakuGossipSub?: PubsubService["pubsub"], options?: Partial, userAgent?: string ): Promise { @@ -56,10 +49,6 @@ export async function defaultLibp2p( /* eslint-enable no-console */ } - const pubsubService: PubsubService = wakuGossipSub - ? { pubsub: wakuGossipSub } - : {}; - const metadataService: MetadataService = shardInfo ? { metadata: wakuMetadata(shardInfo) } : {}; @@ -83,7 +72,6 @@ export async function defaultLibp2p( options?.pingMaxInboundStreams ?? DefaultPingMaxInboundStreams }), ...metadataService, - ...pubsubService, ...options?.services } }) as any as Libp2p; // TODO: make libp2p include it; @@ -109,7 +97,6 @@ export async function createLibp2pAndUpdateOptions( const libp2p = await defaultLibp2p( shardInfo, - wakuGossipSub(options), libp2pOptions, options?.userAgent ); diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 94be6647de..c12e7ab2f6 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -10,7 +10,11 @@ export { utf8ToBytes, bytesToUtf8 } from "@waku/utils/bytes"; export * from "./utils/content_topic.js"; export * from "./waku.js"; -export { createLightNode, defaultLibp2p } from "./create/index.js"; +export { + createLightNode, + defaultLibp2p, + createLibp2pAndUpdateOptions +} from "./create/index.js"; export { wakuLightPush } from "./protocols/light_push.js"; export { wakuFilter } from "./protocols/filter.js"; export { wakuStore } from "./protocols/store.js"; @@ -18,4 +22,3 @@ export { wakuStore } from "./protocols/store.js"; export * as waku from "@waku/core"; export * as utils from "@waku/utils"; export * from "@waku/interfaces"; -export * as relay from "@waku/relay"; diff --git a/packages/sdk/src/relay-node/index.ts b/packages/sdk/src/relay-node/index.ts deleted file mode 100644 index f30eb27113..0000000000 --- a/packages/sdk/src/relay-node/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { type FullNode, type RelayNode } from "@waku/interfaces"; -import { RelayCreateOptions } from "@waku/relay"; - -import { createLibp2pAndUpdateOptions } from "../create/libp2p.js"; -import { CreateWakuNodeOptions, WakuNode, WakuOptions } from "../waku.js"; - -/** - * Create a Waku node that uses Waku Relay to send and receive messages, - * enabling some privacy preserving properties. - * * @remarks - * This function creates a Relay Node using the Waku Relay protocol. - * While it is technically possible to use this function in a browser environment, - * it is not recommended due to potential performance issues and limited browser capabilities. - * If you are developing a browser-based application, consider alternative approaches like creating a Light Node - * or use this function with caution. - */ -export async function createRelayNode( - options: CreateWakuNodeOptions & Partial = { - pubsubTopics: [] - } -): Promise { - const libp2p = await createLibp2pAndUpdateOptions(options); - - return new WakuNode(options as WakuOptions, libp2p, { - relay: true - }) as RelayNode; -} - -/** - * Create a Waku node that uses all Waku protocols. - * - * This helper is not recommended except if: - * - you are interfacing with nwaku v0.11 or below - * - you are doing some form of testing - * - * If you are building a full node, it is recommended to use - * [nwaku](github.com/status-im/nwaku) and its JSON RPC API or wip REST API. - * - * @see https://github.com/status-im/nwaku/issues/1085 - * @internal - */ -export async function createFullNode( - options: CreateWakuNodeOptions & Partial = { - pubsubTopics: [] - } -): Promise { - const libp2p = await createLibp2pAndUpdateOptions(options); - - return new WakuNode(options as WakuOptions, libp2p, { - filter: true, - lightpush: true, - relay: true, - store: true - }) as FullNode; -} diff --git a/packages/sdk/src/waku.ts b/packages/sdk/src/waku.ts index c36735224f..52aa87050c 100644 --- a/packages/sdk/src/waku.ts +++ b/packages/sdk/src/waku.ts @@ -16,7 +16,6 @@ import type { Waku } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; -import { wakuRelay } from "@waku/relay"; import { Logger } from "@waku/utils"; import { wakuFilter } from "./protocols/filter.js"; @@ -61,7 +60,6 @@ type ProtocolsEnabled = { filter?: boolean; lightpush?: boolean; store?: boolean; - relay?: boolean; }; export class WakuNode implements Waku { @@ -76,20 +74,21 @@ export class WakuNode implements Waku { public constructor( options: WakuOptions, libp2p: Libp2p, - protocolsEnabled: ProtocolsEnabled + protocolsEnabled: ProtocolsEnabled, + relay?: IRelay ) { if (options.pubsubTopics.length == 0) { throw new Error("At least one pubsub topic must be provided"); } - this.pubsubTopics = options.pubsubTopics; + this.relay = relay; this.libp2p = libp2p; + this.pubsubTopics = options.pubsubTopics; protocolsEnabled = { filter: false, lightpush: false, store: false, - relay: false, ...protocolsEnabled }; @@ -124,11 +123,6 @@ export class WakuNode implements Waku { this.filter = filter(libp2p); } - if (protocolsEnabled.relay) { - const relay = wakuRelay(this.pubsubTopics); - this.relay = relay(libp2p); - } - log.info( "Waku node created", peerId, diff --git a/packages/tests/package.json b/packages/tests/package.json index 40306efee1..fd099b4ebb 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -54,6 +54,7 @@ "@libp2p/peer-id": "^4.0.4", "@waku/core": "*", "@waku/enr": "*", + "@waku/relay": "*", "@waku/interfaces": "*", "@waku/utils": "*", "app-root-path": "^3.1.0", diff --git a/packages/tests/src/lib/runNodes.ts b/packages/tests/src/lib/runNodes.ts index 908b4e274d..4614f838ad 100644 --- a/packages/tests/src/lib/runNodes.ts +++ b/packages/tests/src/lib/runNodes.ts @@ -5,8 +5,8 @@ import { Protocols, ShardingParams } from "@waku/interfaces"; +import { createRelayNode } from "@waku/relay"; import { createLightNode, WakuNode } from "@waku/sdk"; -import { createRelayNode } from "@waku/sdk/relay"; import { Logger, shardInfoToPubsubTopics } from "@waku/utils"; import { Context } from "mocha"; diff --git a/packages/tests/tests/connection-mananger/connection_state.spec.ts b/packages/tests/tests/connection-mananger/connection_state.spec.ts index a4e3ba640e..1be7dda6c0 100644 --- a/packages/tests/tests/connection-mananger/connection_state.spec.ts +++ b/packages/tests/tests/connection-mananger/connection_state.spec.ts @@ -1,7 +1,7 @@ import { Multiaddr } from "@multiformats/multiaddr"; import { EConnectionStateEvents, LightNode, Protocols } from "@waku/interfaces"; +import { createRelayNode } from "@waku/relay"; import { createLightNode } from "@waku/sdk"; -import { createRelayNode } from "@waku/sdk/relay"; import { expect } from "chai"; import { diff --git a/packages/tests/tests/enr.node.spec.ts b/packages/tests/tests/enr.node.spec.ts index 5db2c41ca5..a67aefce86 100644 --- a/packages/tests/tests/enr.node.spec.ts +++ b/packages/tests/tests/enr.node.spec.ts @@ -2,7 +2,7 @@ import { waitForRemotePeer } from "@waku/core"; import { EnrDecoder } from "@waku/enr"; import type { RelayNode } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk/relay"; +import { createRelayNode } from "@waku/relay"; import { expect } from "chai"; import { diff --git a/packages/tests/tests/relay/interop.node.spec.ts b/packages/tests/tests/relay/interop.node.spec.ts index 09909bb673..12971b4807 100644 --- a/packages/tests/tests/relay/interop.node.spec.ts +++ b/packages/tests/tests/relay/interop.node.spec.ts @@ -1,7 +1,7 @@ import type { PeerId } from "@libp2p/interface"; import { DecodedMessage, waitForRemotePeer } from "@waku/core"; import { Protocols, RelayNode } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk/relay"; +import { createRelayNode } from "@waku/relay"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/relay/multiple_pubsub.node.spec.ts b/packages/tests/tests/relay/multiple_pubsub.node.spec.ts index b6b4d8a4a3..c2b0ea981a 100644 --- a/packages/tests/tests/relay/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/relay/multiple_pubsub.node.spec.ts @@ -11,7 +11,7 @@ import { SingleShardInfo } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk/relay"; +import { createRelayNode } from "@waku/relay"; import { contentTopicToPubsubTopic, pubsubTopicToSingleShardInfo, diff --git a/packages/tests/tests/relay/subscribe.node.spec.ts b/packages/tests/tests/relay/subscribe.node.spec.ts index b234acd53b..a13f60d69d 100644 --- a/packages/tests/tests/relay/subscribe.node.spec.ts +++ b/packages/tests/tests/relay/subscribe.node.spec.ts @@ -1,6 +1,6 @@ import { createDecoder, createEncoder } from "@waku/core"; import { RelayNode } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk/relay"; +import { createRelayNode } from "@waku/relay"; import { utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/relay/utils.ts b/packages/tests/tests/relay/utils.ts index df8cfeee2f..ed24b609ae 100644 --- a/packages/tests/tests/relay/utils.ts +++ b/packages/tests/tests/relay/utils.ts @@ -5,7 +5,7 @@ import { ShardInfo, ShardingParams } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk/relay"; +import { createRelayNode } from "@waku/relay"; import { contentTopicToPubsubTopic, Logger } from "@waku/utils"; import { Context } from "mocha"; diff --git a/packages/tests/tests/store/utils.ts b/packages/tests/tests/store/utils.ts index 4e7fddb993..7f715ca88f 100644 --- a/packages/tests/tests/store/utils.ts +++ b/packages/tests/tests/store/utils.ts @@ -116,8 +116,9 @@ export async function startAndConnectLightNode( const wakuConnections = waku.libp2p.getConnections(); const nwakuPeers = await instance.peers(); + // TODO: return throw when nwaku releases following fix https://github.com/waku-org/nwaku/pull/2923 if (wakuConnections.length < 1 || nwakuPeers.length < 1) { - throw new Error( + log.error( `Expected at least 1 peer in each node. Got waku connections: ${wakuConnections.length} and nwaku: ${nwakuPeers.length}` ); } diff --git a/packages/tests/tests/wait_for_remote_peer.node.spec.ts b/packages/tests/tests/wait_for_remote_peer.node.spec.ts index 2e50b036d3..3b0d52f7c3 100644 --- a/packages/tests/tests/wait_for_remote_peer.node.spec.ts +++ b/packages/tests/tests/wait_for_remote_peer.node.spec.ts @@ -1,8 +1,8 @@ import { waitForRemotePeer } from "@waku/core"; import type { LightNode, RelayNode } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; +import { createRelayNode } from "@waku/relay"; import { createLightNode } from "@waku/sdk"; -import { createRelayNode } from "@waku/sdk/relay"; import { expect } from "chai"; import { diff --git a/packages/tests/tests/waku.node.spec.ts b/packages/tests/tests/waku.node.spec.ts index 1dc556ebdc..92931e4254 100644 --- a/packages/tests/tests/waku.node.spec.ts +++ b/packages/tests/tests/waku.node.spec.ts @@ -8,12 +8,12 @@ import { createDecoder, createEncoder } from "@waku/message-encryption/symmetric"; +import { createRelayNode } from "@waku/relay"; import { createLightNode, createEncoder as createPlainEncoder, DefaultUserAgent } from "@waku/sdk"; -import { createRelayNode } from "@waku/sdk/relay"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai";