From dd1ce6d64b33bf344d42cc352a584f89ed20b19a Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 12:53:35 +0530 Subject: [PATCH 01/18] move protocol result type to interfaces --- packages/core/src/lib/light_push/index.ts | 22 ++++++++++------------ packages/interfaces/src/protocols.ts | 9 ++++++++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/core/src/lib/light_push/index.ts b/packages/core/src/lib/light_push/index.ts index 62d922c805..8142bc3320 100644 --- a/packages/core/src/lib/light_push/index.ts +++ b/packages/core/src/lib/light_push/index.ts @@ -1,13 +1,13 @@ -import type { Peer, PeerId, Stream } from "@libp2p/interface"; +import type { Peer, Stream } from "@libp2p/interface"; import { - Failure, - IBaseProtocolCore, - IEncoder, - IMessage, - Libp2p, - ProtocolCreateOptions, + type IBaseProtocolCore, + type IEncoder, + type IMessage, + type Libp2p, + type ProtocolCreateOptions, ProtocolError, - ProtocolResult + ProtocolRequestResult, + type ResultWithError } from "@waku/interfaces"; import { PushResponse } from "@waku/proto"; import { isMessageSizeUnderCap } from "@waku/utils"; @@ -26,9 +26,7 @@ const log = new Logger("light-push"); export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1"; export { PushResponse }; -type PreparePushMessageResult = ProtocolResult<"query", PushRpc>; - -type CoreSendResult = ProtocolResult<"success", PeerId, "failure", Failure>; +type PreparePushMessageResult = ResultWithError<"query", PushRpc>; /** * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/). @@ -84,7 +82,7 @@ export class LightPushCore extends BaseProtocol implements IBaseProtocolCore { encoder: IEncoder, message: IMessage, peer: Peer - ): Promise { + ): Promise { const { query, error: preparationError } = await this.preparePushMessage( encoder, message diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 012a7834af..60bff53e9c 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -105,7 +105,7 @@ export type Callback = ( // SV = success value type // EK = error key name (default: "error") // EV = error value type (default: ProtocolError) -export type ProtocolResult< +export type ResultWithError< SK extends string, SV, EK extends string = "error", @@ -184,3 +184,10 @@ export interface SendResult { failures?: Failure[]; successes: PeerId[]; } + +export type ProtocolRequestResult = ResultWithError< + "success", + PeerId, + "failure", + Failure +>; From 8226ee3e8b3461e0c57c896cbecbb599f74e7d92 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 12:54:01 +0530 Subject: [PATCH 02/18] chore: update type names for verbosity --- packages/core/src/lib/metadata/index.ts | 10 ++++++---- packages/interfaces/src/metadata.ts | 8 ++++---- packages/interfaces/src/peer_exchange.ts | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/core/src/lib/metadata/index.ts b/packages/core/src/lib/metadata/index.ts index 4fed198168..e402b7d37c 100644 --- a/packages/core/src/lib/metadata/index.ts +++ b/packages/core/src/lib/metadata/index.ts @@ -3,9 +3,9 @@ import { IncomingStreamData } from "@libp2p/interface"; import { type IMetadata, type Libp2pComponents, + type MetadataQueryResult, type PeerIdStr, ProtocolError, - QueryResult, type ShardInfo } from "@waku/interfaces"; import { proto_metadata } from "@waku/proto"; @@ -74,7 +74,7 @@ class Metadata extends BaseProtocol implements IMetadata { /** * Make a metadata query to a peer */ - async query(peerId: PeerId): Promise { + async query(peerId: PeerId): Promise { const request = proto_metadata.WakuMetadataRequest.encode(this.shardInfo); const peer = await this.peerStore.get(peerId); @@ -112,7 +112,9 @@ class Metadata extends BaseProtocol implements IMetadata { }; } - public async confirmOrAttemptHandshake(peerId: PeerId): Promise { + public async confirmOrAttemptHandshake( + peerId: PeerId + ): Promise { const shardInfo = this.handshakesConfirmed.get(peerId.toString()); if (shardInfo) { return { @@ -126,7 +128,7 @@ class Metadata extends BaseProtocol implements IMetadata { private decodeMetadataResponse( encodedResponse: Uint8ArrayList[] - ): QueryResult { + ): MetadataQueryResult { const bytes = new Uint8ArrayList(); encodedResponse.forEach((chunk) => { diff --git a/packages/interfaces/src/metadata.ts b/packages/interfaces/src/metadata.ts index 47d561b936..51f17176de 100644 --- a/packages/interfaces/src/metadata.ts +++ b/packages/interfaces/src/metadata.ts @@ -3,15 +3,15 @@ import type { PeerId } from "@libp2p/interface"; import { type ShardInfo } from "./enr.js"; import type { IBaseProtocolCore, - ProtocolResult, + ResultWithError, ShardingParams } from "./protocols.js"; -export type QueryResult = ProtocolResult<"shardInfo", ShardInfo>; +export type MetadataQueryResult = ResultWithError<"shardInfo", ShardInfo>; // IMetadata always has shardInfo defined while it is optionally undefined in IBaseProtocol export interface IMetadata extends Omit { shardInfo: ShardingParams; - confirmOrAttemptHandshake(peerId: PeerId): Promise; - query(peerId: PeerId): Promise; + confirmOrAttemptHandshake(peerId: PeerId): Promise; + query(peerId: PeerId): Promise; } diff --git a/packages/interfaces/src/peer_exchange.ts b/packages/interfaces/src/peer_exchange.ts index 9f9c624ab5..a8b1609ff6 100644 --- a/packages/interfaces/src/peer_exchange.ts +++ b/packages/interfaces/src/peer_exchange.ts @@ -3,13 +3,13 @@ import type { PeerStore } from "@libp2p/interface"; import type { ConnectionManager } from "@libp2p/interface-internal"; import { IEnr } from "./enr.js"; -import { IBaseProtocolCore, ProtocolResult } from "./protocols.js"; +import { IBaseProtocolCore, ResultWithError } from "./protocols.js"; export interface IPeerExchange extends IBaseProtocolCore { - query(params: PeerExchangeQueryParams): Promise; + query(params: PeerExchangeQueryParams): Promise; } -export type PeerExchangeResult = ProtocolResult<"peerInfos", PeerInfo[]>; +export type PeerExchangeQueryResult = ResultWithError<"peerInfos", PeerInfo[]>; export interface PeerExchangeQueryParams { numPeers: number; From 2303e792c38d33dc08fdbb41cc62857558ce2f0e Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 12:54:28 +0530 Subject: [PATCH 03/18] feat(filter-core): convert error throws to return types --- packages/core/src/lib/filter/index.ts | 188 ++++++++++++++++++++------ 1 file changed, 147 insertions(+), 41 deletions(-) diff --git a/packages/core/src/lib/filter/index.ts b/packages/core/src/lib/filter/index.ts index 790a1953d4..8e44cab128 100644 --- a/packages/core/src/lib/filter/index.ts +++ b/packages/core/src/lib/filter/index.ts @@ -1,17 +1,20 @@ -import type { Peer } from "@libp2p/interface"; +import type { Peer, Stream } from "@libp2p/interface"; import type { IncomingStreamData } from "@libp2p/interface-internal"; -import type { - ContentTopic, - IBaseProtocolCore, - Libp2p, - ProtocolCreateOptions, - PubsubTopic +import { + type ContentTopic, + type IBaseProtocolCore, + type Libp2p, + type ProtocolCreateOptions, + ProtocolError, + type ProtocolRequestResult, + type PubsubTopic } from "@waku/interfaces"; import { WakuMessage } from "@waku/proto"; import { Logger } from "@waku/utils"; import all from "it-all"; import * as lp from "it-length-prefixed"; import { pipe } from "it-pipe"; +import { Uint8ArrayList } from "uint8arraylist"; import { BaseProtocol } from "../base_protocol.js"; @@ -90,7 +93,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] - ): Promise { + ): Promise { const stream = await this.getStream(peer); const request = FilterSubscribeRpc.createSubscribeRequest( @@ -107,36 +110,87 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { ); if (!res || !res.length) { - throw Error( - `No response received for request ${request.requestId}: ${res}` - ); + return { + failure: { + error: ProtocolError.REMOTE_PEER_FAULT, + peerId: peer.id + }, + success: null + }; } const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice()); if (statusCode < 200 || statusCode >= 300) { - throw new Error( + log.error( `Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}` ); + return { + failure: { + error: ProtocolError.REMOTE_PEER_REJECTED, + peerId: peer.id + }, + success: null + }; } + + return { + failure: null, + success: peer.id + }; } async unsubscribe( pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] - ): Promise { - const stream = await this.getStream(peer); + ): Promise { + let stream: Stream | undefined; + try { + stream = await this.getStream(peer); + } catch (error) { + log.error( + `Failed to get a stream for remote peer${peer.id.toString()}`, + error + ); + return { + success: null, + failure: { + error: ProtocolError.REMOTE_PEER_FAULT, + peerId: peer.id + } + }; + } + const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest( pubsubTopic, contentTopics ); - await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink); + try { + await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink); + } catch (error) { + log.error("Failed to send unsubscribe request", error); + return { + success: null, + failure: { + error: ProtocolError.GENERIC_FAIL, + peerId: peer.id + } + }; + } + + return { + success: peer.id, + failure: null + }; } - async unsubscribeAll(pubsubTopic: PubsubTopic, peer: Peer): Promise { + async unsubscribeAll( + pubsubTopic: PubsubTopic, + peer: Peer + ): Promise { const stream = await this.getStream(peer); const request = FilterSubscribeRpc.createUnsubscribeAllRequest(pubsubTopic); @@ -150,53 +204,105 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { ); if (!res || !res.length) { - throw Error( - `No response received for request ${request.requestId}: ${res}` - ); + return { + failure: { + error: ProtocolError.REMOTE_PEER_FAULT, + peerId: peer.id + }, + success: null + }; } const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice()); if (statusCode < 200 || statusCode >= 300) { - throw new Error( + log.error( `Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}` ); + return { + failure: { + error: ProtocolError.REMOTE_PEER_REJECTED, + peerId: peer.id + }, + success: null + }; } + + return { + failure: null, + success: peer.id + }; } - async ping(peer: Peer): Promise { - const stream = await this.getStream(peer); + async ping(peer: Peer): Promise { + let stream: Stream | undefined; + try { + stream = await this.getStream(peer); + } catch (error) { + log.error( + `Failed to get a stream for remote peer${peer.id.toString()}`, + error + ); + return { + success: null, + failure: { + error: ProtocolError.REMOTE_PEER_FAULT, + peerId: peer.id + } + }; + } const request = FilterSubscribeRpc.createSubscriberPingRequest(); + let res: Uint8ArrayList[] | undefined; try { - const res = await pipe( + res = await pipe( [request.encode()], lp.encode, stream, lp.decode, async (source) => await all(source) ); - - if (!res || !res.length) { - throw Error( - `No response received for request ${request.requestId}: ${res}` - ); - } - - const { statusCode, requestId, statusDesc } = - FilterSubscribeResponse.decode(res[0].slice()); - - if (statusCode < 200 || statusCode >= 300) { - throw new Error( - `Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}` - ); - } - log.info(`Ping successful for peer ${peer.id.toString()}`); } catch (error) { - log.error("Error pinging: ", error); - throw error; // Rethrow the actual error instead of wrapping it + log.error("Failed to send ping request", error); + return { + success: null, + failure: { + error: ProtocolError.GENERIC_FAIL, + peerId: peer.id + } + }; + } + + if (!res || !res.length) { + return { + success: null, + failure: { + error: ProtocolError.REMOTE_PEER_FAULT, + peerId: peer.id + } + }; + } + + const { statusCode, requestId, statusDesc } = + FilterSubscribeResponse.decode(res[0].slice()); + + if (statusCode < 200 || statusCode >= 300) { + log.error( + `Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}` + ); + return { + success: null, + failure: { + error: ProtocolError.REMOTE_PEER_REJECTED, + peerId: peer.id + } + }; } + return { + success: peer.id, + failure: null + }; } } From 07ed52fc9fcd3baeb63cbcbe16210ad7810278d4 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 14:09:04 +0530 Subject: [PATCH 04/18] chore: update types & imports --- packages/core/src/lib/filter/index.ts | 10 +++--- packages/core/src/lib/light_push/index.ts | 8 ++--- packages/interfaces/src/metadata.ts | 9 ++--- packages/interfaces/src/misc.ts | 21 ++++++++++++ packages/interfaces/src/peer_exchange.ts | 5 +-- packages/interfaces/src/protocols.ts | 42 ++++++++--------------- packages/interfaces/src/sender.ts | 4 +-- packages/sdk/src/protocols/light_push.ts | 4 +-- 8 files changed, 54 insertions(+), 49 deletions(-) diff --git a/packages/core/src/lib/filter/index.ts b/packages/core/src/lib/filter/index.ts index 8e44cab128..445b1167c8 100644 --- a/packages/core/src/lib/filter/index.ts +++ b/packages/core/src/lib/filter/index.ts @@ -2,11 +2,11 @@ import type { Peer, Stream } from "@libp2p/interface"; import type { IncomingStreamData } from "@libp2p/interface-internal"; import { type ContentTopic, + CoreProtocolResult, type IBaseProtocolCore, type Libp2p, type ProtocolCreateOptions, ProtocolError, - type ProtocolRequestResult, type PubsubTopic } from "@waku/interfaces"; import { WakuMessage } from "@waku/proto"; @@ -93,7 +93,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] - ): Promise { + ): Promise { const stream = await this.getStream(peer); const request = FilterSubscribeRpc.createSubscribeRequest( @@ -145,7 +145,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] - ): Promise { + ): Promise { let stream: Stream | undefined; try { stream = await this.getStream(peer); @@ -190,7 +190,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { async unsubscribeAll( pubsubTopic: PubsubTopic, peer: Peer - ): Promise { + ): Promise { const stream = await this.getStream(peer); const request = FilterSubscribeRpc.createUnsubscribeAllRequest(pubsubTopic); @@ -235,7 +235,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { }; } - async ping(peer: Peer): Promise { + async ping(peer: Peer): Promise { let stream: Stream | undefined; try { stream = await this.getStream(peer); diff --git a/packages/core/src/lib/light_push/index.ts b/packages/core/src/lib/light_push/index.ts index 8142bc3320..2b8fb3ebd2 100644 --- a/packages/core/src/lib/light_push/index.ts +++ b/packages/core/src/lib/light_push/index.ts @@ -1,13 +1,13 @@ import type { Peer, Stream } from "@libp2p/interface"; import { + type CoreProtocolResult, type IBaseProtocolCore, type IEncoder, type IMessage, type Libp2p, type ProtocolCreateOptions, ProtocolError, - ProtocolRequestResult, - type ResultWithError + type ThisOrThat } from "@waku/interfaces"; import { PushResponse } from "@waku/proto"; import { isMessageSizeUnderCap } from "@waku/utils"; @@ -26,7 +26,7 @@ const log = new Logger("light-push"); export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1"; export { PushResponse }; -type PreparePushMessageResult = ResultWithError<"query", PushRpc>; +type PreparePushMessageResult = ThisOrThat<"query", PushRpc>; /** * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/). @@ -82,7 +82,7 @@ export class LightPushCore extends BaseProtocol implements IBaseProtocolCore { encoder: IEncoder, message: IMessage, peer: Peer - ): Promise { + ): Promise { const { query, error: preparationError } = await this.preparePushMessage( encoder, message diff --git a/packages/interfaces/src/metadata.ts b/packages/interfaces/src/metadata.ts index 51f17176de..31f0ced66e 100644 --- a/packages/interfaces/src/metadata.ts +++ b/packages/interfaces/src/metadata.ts @@ -1,13 +1,10 @@ import type { PeerId } from "@libp2p/interface"; import { type ShardInfo } from "./enr.js"; -import type { - IBaseProtocolCore, - ResultWithError, - ShardingParams -} from "./protocols.js"; +import { ThisOrThat } from "./misc.js"; +import type { IBaseProtocolCore, ShardingParams } from "./protocols.js"; -export type MetadataQueryResult = ResultWithError<"shardInfo", ShardInfo>; +export type MetadataQueryResult = ThisOrThat<"shardInfo", ShardInfo>; // IMetadata always has shardInfo defined while it is optionally undefined in IBaseProtocol export interface IMetadata extends Omit { diff --git a/packages/interfaces/src/misc.ts b/packages/interfaces/src/misc.ts index 4382c61566..91170c88fa 100644 --- a/packages/interfaces/src/misc.ts +++ b/packages/interfaces/src/misc.ts @@ -1,4 +1,5 @@ import type { IDecodedMessage } from "./message.js"; +import { ProtocolError } from "./protocols.js"; export interface IAsyncIterator { iterator: AsyncIterator; @@ -11,3 +12,23 @@ export type PubsubTopic = string; export type ContentTopic = string; export type PeerIdStr = string; + +// SK = success key name +// SV = success value type +// EK = error key name (default: "error") +// EV = error value type (default: ProtocolError) +export type ThisOrThat< + SK extends string, + SV, + EK extends string = "error", + EV = ProtocolError +> = + | ({ [key in SK]: SV } & { [key in EK]: null }) + | ({ [key in SK]: null } & { [key in EK]: EV }); + +export type ThisAndThat< + SK extends string, + SV, + EK extends string = "error", + EV = ProtocolError +> = { [key in SK]: SV } & { [key in EK]: EV }; diff --git a/packages/interfaces/src/peer_exchange.ts b/packages/interfaces/src/peer_exchange.ts index a8b1609ff6..2078899cae 100644 --- a/packages/interfaces/src/peer_exchange.ts +++ b/packages/interfaces/src/peer_exchange.ts @@ -3,13 +3,14 @@ import type { PeerStore } from "@libp2p/interface"; import type { ConnectionManager } from "@libp2p/interface-internal"; import { IEnr } from "./enr.js"; -import { IBaseProtocolCore, ResultWithError } from "./protocols.js"; +import { ThisOrThat } from "./misc.js"; +import { IBaseProtocolCore } from "./protocols.js"; export interface IPeerExchange extends IBaseProtocolCore { query(params: PeerExchangeQueryParams): Promise; } -export type PeerExchangeQueryResult = ResultWithError<"peerInfos", PeerInfo[]>; +export type PeerExchangeQueryResult = ThisOrThat<"peerInfos", PeerInfo[]>; export interface PeerExchangeQueryParams { numPeers: number; diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 60bff53e9c..914b3ca14f 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -5,7 +5,7 @@ import type { Peer, PeerStore } from "@libp2p/interface"; import type { ShardInfo } from "./enr.js"; import type { CreateLibp2pOptions } from "./libp2p.js"; import type { IDecodedMessage } from "./message.js"; -import { PubsubTopic } from "./misc.js"; +import { PubsubTopic, ThisAndThat, ThisOrThat } from "./misc.js"; export enum Protocols { Relay = "relay", @@ -101,27 +101,6 @@ export type Callback = ( msg: T ) => void | Promise; -// SK = success key name -// SV = success value type -// EK = error key name (default: "error") -// EV = error value type (default: ProtocolError) -export type ResultWithError< - SK extends string, - SV, - EK extends string = "error", - EV = ProtocolError -> = - | ({ - [key in SK]: SV; - } & { - [key in EK]: null; - }) - | ({ - [key in SK]: null; - } & { - [key in EK]: EV; - }); - export enum ProtocolError { /** Could not determine the origin of the fault. Best to check connectivity and try again */ GENERIC_FAIL = "Generic error", @@ -150,6 +129,11 @@ export enum ProtocolError { * Please ensure that the PubsubTopic is used when initializing the Waku node. */ TOPIC_NOT_CONFIGURED = "Topic not configured", + /** + * The pubsub topic configured on the decoder does not match the pubsub topic setup on the protocol. + * Ensure that the pubsub topic used for decoder creation is the same as the one used for protocol. + */ + TOPIC_DECODER_MISMATCH = "Topic decoder mismatch", /** * Failure to find a peer with suitable protocols. This may due to a connection issue. * Mitigation can be: retrying after a given time period, display connectivity issue @@ -180,14 +164,16 @@ export interface Failure { peerId?: PeerId; } -export interface SendResult { - failures?: Failure[]; - successes: PeerId[]; -} - -export type ProtocolRequestResult = ResultWithError< +export type CoreProtocolResult = ThisOrThat< "success", PeerId, "failure", Failure >; + +export type SDKProtocolResult = ThisAndThat< + "successes", + PeerId[], + "failures", + Failure[] +>; diff --git a/packages/interfaces/src/sender.ts b/packages/interfaces/src/sender.ts index ab7e6d1b8c..2dbe72def9 100644 --- a/packages/interfaces/src/sender.ts +++ b/packages/interfaces/src/sender.ts @@ -1,6 +1,6 @@ import type { IEncoder, IMessage } from "./message.js"; -import type { SendResult } from "./protocols.js"; +import { SDKProtocolResult } from "./protocols.js"; export interface ISender { - send: (encoder: IEncoder, message: IMessage) => Promise; + send: (encoder: IEncoder, message: IMessage) => Promise; } diff --git a/packages/sdk/src/protocols/light_push.ts b/packages/sdk/src/protocols/light_push.ts index 6f61c71989..67e2117df2 100644 --- a/packages/sdk/src/protocols/light_push.ts +++ b/packages/sdk/src/protocols/light_push.ts @@ -8,7 +8,7 @@ import { type Libp2p, type ProtocolCreateOptions, ProtocolError, - type SendResult + SDKProtocolResult } from "@waku/interfaces"; import { ensurePubsubTopicIsConfigured, Logger } from "@waku/utils"; @@ -24,7 +24,7 @@ class LightPushSDK extends BaseProtocolSDK implements ILightPushSDK { this.protocol = new LightPushCore(libp2p, options); } - async send(encoder: IEncoder, message: IMessage): Promise { + async send(encoder: IEncoder, message: IMessage): Promise { const successes: PeerId[] = []; const failures: Failure[] = []; From f03e86d581fdc75f765b851be9b3db85fd253e44 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 14:19:40 +0530 Subject: [PATCH 05/18] update Filter API --- packages/interfaces/src/filter.ts | 19 ++-- packages/sdk/src/protocols/filter.ts | 110 +++++++++++++----------- packages/sdk/src/utils/content_topic.ts | 11 +-- packages/sdk/src/waku.ts | 4 +- 4 files changed, 79 insertions(+), 65 deletions(-) diff --git a/packages/interfaces/src/filter.ts b/packages/interfaces/src/filter.ts index 1565ec482d..54194e781d 100644 --- a/packages/interfaces/src/filter.ts +++ b/packages/interfaces/src/filter.ts @@ -5,7 +5,8 @@ import type { ContentTopic, PubsubTopic } from "./misc.js"; import type { Callback, IBaseProtocolCore, - IBaseProtocolSDK + IBaseProtocolSDK, + SDKProtocolResult } from "./protocols.js"; import type { IReceiver } from "./receiver.js"; @@ -13,25 +14,25 @@ export type ContentFilter = { contentTopic: string; }; -export interface IFilterSubscription { +export type IFilter = IReceiver & IBaseProtocolCore; + +export interface IFilterSubscriptionSDK { subscribe( decoders: IDecoder | IDecoder[], callback: Callback - ): Promise; + ): Promise; - unsubscribe(contentTopics: ContentTopic[]): Promise; + unsubscribe(contentTopics: ContentTopic[]): Promise; - ping(): Promise; + ping(): Promise; - unsubscribeAll(): Promise; + unsubscribeAll(): Promise; } -export type IFilter = IReceiver & IBaseProtocolCore; - export type IFilterSDK = IReceiver & IBaseProtocolSDK & { protocol: IBaseProtocolCore } & { createSubscription( pubsubTopicShardInfo?: SingleShardInfo | PubsubTopic, peerId?: PeerId - ): Promise; + ): Promise; }; diff --git a/packages/sdk/src/protocols/filter.ts b/packages/sdk/src/protocols/filter.ts index 83883f5cae..a22ce76d0c 100644 --- a/packages/sdk/src/protocols/filter.ts +++ b/packages/sdk/src/protocols/filter.ts @@ -3,6 +3,7 @@ import { FilterCore } from "@waku/core"; import { type Callback, ContentTopic, + CoreProtocolResult, DefaultPubsubTopic, type IAsyncIterator, type IDecodedMessage, @@ -11,7 +12,9 @@ import { IProtoMessage, type Libp2p, type ProtocolCreateOptions, + ProtocolError, type PubsubTopic, + SDKProtocolResult, type SingleShardInfo, type Unsubscribe } from "@waku/interfaces"; @@ -57,28 +60,37 @@ export class SubscriptionManager { async subscribe( decoders: IDecoder | IDecoder[], callback: Callback - ): Promise { + ): Promise { const decodersArray = Array.isArray(decoders) ? decoders : [decoders]; // check that all decoders are configured for the same pubsub topic as this subscription - decodersArray.forEach((decoder) => { + for (const decoder of decodersArray) { if (decoder.pubsubTopic !== this.pubsubTopic) { - throw new Error( - `Pubsub topic not configured: decoder is configured for pubsub topic ${decoder.pubsubTopic} but this subscription is for pubsub topic ${this.pubsubTopic}. Please create a new Subscription for the different pubsub topic.` - ); + return { + failures: [ + { + error: ProtocolError.TOPIC_DECODER_MISMATCH + } + ], + successes: [] + }; } - }); + } const decodersGroupedByCT = groupByContentTopic(decodersArray); const contentTopics = Array.from(decodersGroupedByCT.keys()); const promises = this.peers.map(async (peer) => { - await this.protocol.subscribe(this.pubsubTopic, peer, contentTopics); + return await this.protocol.subscribe( + this.pubsubTopic, + peer, + contentTopics + ); }); const results = await Promise.allSettled(promises); - this.handleErrors(results, "subscribe"); + const finalResult = this.handleResult(results, "subscribe"); // Save the callback functions by content topics so they // can easily be removed (reciprocally replaced) if `unsubscribe` (reciprocally `subscribe`) @@ -95,42 +107,50 @@ export class SubscriptionManager { // purpose as the user may call `subscribe` to refresh the subscription this.subscriptionCallbacks.set(contentTopic, subscriptionCallback); }); + + return finalResult; } - async unsubscribe(contentTopics: ContentTopic[]): Promise { + async unsubscribe(contentTopics: ContentTopic[]): Promise { const promises = this.peers.map(async (peer) => { - await this.protocol.unsubscribe(this.pubsubTopic, peer, contentTopics); + const response = await this.protocol.unsubscribe( + this.pubsubTopic, + peer, + contentTopics + ); contentTopics.forEach((contentTopic: string) => { this.subscriptionCallbacks.delete(contentTopic); }); + + return response; }); const results = await Promise.allSettled(promises); - this.handleErrors(results, "unsubscribe"); + return this.handleResult(results, "unsubscribe"); } - async ping(): Promise { + async ping(): Promise { const promises = this.peers.map(async (peer) => { - await this.protocol.ping(peer); + return await this.protocol.ping(peer); }); const results = await Promise.allSettled(promises); - this.handleErrors(results, "ping"); + return this.handleResult(results, "ping"); } - async unsubscribeAll(): Promise { + async unsubscribeAll(): Promise { const promises = this.peers.map(async (peer) => { - await this.protocol.unsubscribeAll(this.pubsubTopic, peer); + return await this.protocol.unsubscribeAll(this.pubsubTopic, peer); }); const results = await Promise.allSettled(promises); this.subscriptionCallbacks.clear(); - this.handleErrors(results, "unsubscribeAll"); + return this.handleResult(results, "unsubscribeAll"); } async processIncomingMessage(message: WakuMessage): Promise { @@ -159,40 +179,32 @@ export class SubscriptionManager { await pushMessage(subscriptionCallback, this.pubsubTopic, message); } - // Filter out only the rejected promises and extract & handle their reasons - private handleErrors( - results: PromiseSettledResult[], + private handleResult( + results: PromiseSettledResult[], type: "ping" | "subscribe" | "unsubscribe" | "unsubscribeAll" - ): void { - const errors = results - .filter( - (result): result is PromiseRejectedResult => - result.status === "rejected" - ) - .map((rejectedResult) => rejectedResult.reason); - - if (errors.length === this.peers.length) { - const errorCounts = new Map(); - // TODO: streamline error logging with https://github.com/orgs/waku-org/projects/2/views/1?pane=issue&itemId=42849952 - errors.forEach((error) => { - const message = error instanceof Error ? error.message : String(error); - errorCounts.set(message, (errorCounts.get(message) || 0) + 1); - }); - - const uniqueErrorMessages = Array.from( - errorCounts, - ([message, count]) => `${message} (occurred ${count} times)` - ).join(", "); - throw new Error(`Error ${type} all peers: ${uniqueErrorMessages}`); - } else if (errors.length > 0) { - // TODO: handle renewing faulty peers with new peers (https://github.com/waku-org/js-waku/issues/1463) - log.warn( - `Some ${type} failed. These will be refreshed with new peers`, - errors - ); - } else { - log.info(`${type} successful for all peers`); + ): SDKProtocolResult { + const result: SDKProtocolResult = { failures: [], successes: [] }; + + for (const promiseResult of results) { + if (promiseResult.status === "rejected") { + log.error( + `Failed to resolve ${type} promise successfully: `, + promiseResult.reason + ); + result.failures.push({ error: ProtocolError.GENERIC_FAIL }); + } else { + const coreResult = promiseResult.value; + if (coreResult.failure) { + result.failures.push(coreResult.failure); + } else { + result.successes.push(coreResult.success); + } + } } + + // TODO: handle renewing faulty peers with new peers (https://github.com/waku-org/js-waku/issues/1463) + + return result; } } diff --git a/packages/sdk/src/utils/content_topic.ts b/packages/sdk/src/utils/content_topic.ts index 62a3e7fb2a..dd09940641 100644 --- a/packages/sdk/src/utils/content_topic.ts +++ b/packages/sdk/src/utils/content_topic.ts @@ -3,7 +3,7 @@ import { createDecoder, DecodedMessage, waitForRemotePeer } from "@waku/core"; import { Callback, IDecoder, - IFilterSubscription, + IFilterSubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; @@ -27,7 +27,7 @@ async function prepareSubscription( peer: Multiaddr ): Promise<{ decoder: IDecoder; - subscription: IFilterSubscription; + subscription: IFilterSubscriptionSDK; }> { // Validate that the Waku node matches assumptions if (!waku.filter) { @@ -86,10 +86,11 @@ export async function streamContentTopic( controller.enqueue(message); }); }, - cancel() { - return subscription.unsubscribe([contentTopic]); + async cancel() { + await subscription.unsubscribe([contentTopic]); } }); + return [messageStream, opts.waku]; } @@ -105,7 +106,7 @@ export async function subscribeToContentTopic( contentTopic: string, callback: Callback, opts: CreateTopicOptions -): Promise<{ subscription: IFilterSubscription; waku: LightNode }> { +): Promise<{ subscription: IFilterSubscriptionSDK; waku: LightNode }> { opts.waku = opts.waku ?? (await createLightNode({ diff --git a/packages/sdk/src/waku.ts b/packages/sdk/src/waku.ts index a68a317611..ed4f4363f8 100644 --- a/packages/sdk/src/waku.ts +++ b/packages/sdk/src/waku.ts @@ -5,7 +5,7 @@ import { ConnectionManager, DecodedMessage } from "@waku/core"; import type { Callback, IFilterSDK, - IFilterSubscription, + IFilterSubscriptionSDK, ILightPushSDK, IRelay, IStoreSDK, @@ -192,7 +192,7 @@ export class WakuNode implements Waku { contentTopic: string, peer: Multiaddr, callback: Callback - ): Promise { + ): Promise { return ( await subscribeToContentTopic(contentTopic, callback, { waku: this as LightNode, From b6c116e7b831b6608d6d5bd959636efce49fd4eb Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 17:50:12 +0530 Subject: [PATCH 06/18] chore: update createSubscription --- packages/interfaces/src/filter.ts | 14 +++++++++--- packages/sdk/src/protocols/filter.ts | 33 +++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/packages/interfaces/src/filter.ts b/packages/interfaces/src/filter.ts index 54194e781d..6f0857735d 100644 --- a/packages/interfaces/src/filter.ts +++ b/packages/interfaces/src/filter.ts @@ -1,11 +1,12 @@ import type { PeerId } from "@libp2p/interface"; import type { IDecodedMessage, IDecoder, SingleShardInfo } from "./message.js"; -import type { ContentTopic, PubsubTopic } from "./misc.js"; +import type { ContentTopic, PubsubTopic, ThisOrThat } from "./misc.js"; import type { Callback, IBaseProtocolCore, IBaseProtocolSDK, + ProtocolError, SDKProtocolResult } from "./protocols.js"; import type { IReceiver } from "./receiver.js"; @@ -16,7 +17,7 @@ export type ContentFilter = { export type IFilter = IReceiver & IBaseProtocolCore; -export interface IFilterSubscriptionSDK { +export interface ISubscriptionSDK { subscribe( decoders: IDecoder | IDecoder[], callback: Callback @@ -34,5 +35,12 @@ export type IFilterSDK = IReceiver & createSubscription( pubsubTopicShardInfo?: SingleShardInfo | PubsubTopic, peerId?: PeerId - ): Promise; + ): Promise; }; + +export type CreateSubscriptionResult = ThisOrThat< + "subscription", + ISubscriptionSDK, + "error", + ProtocolError +>; diff --git a/packages/sdk/src/protocols/filter.ts b/packages/sdk/src/protocols/filter.ts index a22ce76d0c..dd7cc5aede 100644 --- a/packages/sdk/src/protocols/filter.ts +++ b/packages/sdk/src/protocols/filter.ts @@ -4,12 +4,14 @@ import { type Callback, ContentTopic, CoreProtocolResult, + CreateSubscriptionResult, DefaultPubsubTopic, type IAsyncIterator, type IDecodedMessage, type IDecoder, type IFilterSDK, IProtoMessage, + ISubscriptionSDK, type Libp2p, type ProtocolCreateOptions, ProtocolError, @@ -37,7 +39,7 @@ type SubscriptionCallback = { const log = new Logger("sdk:filter"); -export class SubscriptionManager { +export class SubscriptionManager implements ISubscriptionSDK { private readonly pubsubTopic: PubsubTopic; readonly peers: Peer[]; readonly receivedMessagesHashStr: string[] = []; @@ -258,7 +260,7 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { */ async createSubscription( pubsubTopicShardInfo: SingleShardInfo | PubsubTopic = DefaultPubsubTopic - ): Promise { + ): Promise { const pubsubTopic = typeof pubsubTopicShardInfo == "string" ? pubsubTopicShardInfo @@ -266,9 +268,21 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { ensurePubsubTopicIsConfigured(pubsubTopic, this.protocol.pubsubTopics); - const peers = await this.protocol.getPeers(); + let peers: Peer[] = []; + try { + peers = await this.protocol.getPeers(); + } catch (error) { + log.error("Error getting peers to initiate subscription: ", error); + return { + error: ProtocolError.GENERIC_FAIL, + subscription: null + }; + } if (peers.length === 0) { - throw new Error("No peer found to initiate subscription."); + return { + error: ProtocolError.NO_PEER_AVAILABLE, + subscription: null + }; } log.info( @@ -283,7 +297,10 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { new SubscriptionManager(pubsubTopic, peers, this.protocol) ); - return subscription; + return { + error: null, + subscription + }; } //TODO: remove this dependency on IReceiver @@ -306,7 +323,11 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { decoders: IDecoder | IDecoder[], callback: Callback ): Promise { - const subscription = await this.createSubscription(); + const { subscription } = await this.createSubscription(); + //TODO: throw will be removed when `subscribe()` is removed from IReceiver + if (!subscription) { + throw new Error("Failed to create subscription"); + } await subscription.subscribe(decoders, callback); From 2688ec92b0120b2851ef7f65f3fce6ff078d3035 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 17:50:51 +0530 Subject: [PATCH 07/18] chore: update imports & rename --- .../discovery/src/peer-exchange/waku_peer_exchange.ts | 6 ++++-- .../src/peer-exchange/waku_peer_exchange_discovery.ts | 6 +++--- packages/relay/src/index.ts | 10 +++++++--- packages/sdk/src/utils/content_topic.ts | 11 +++++++---- packages/sdk/src/waku.ts | 4 ++-- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/discovery/src/peer-exchange/waku_peer_exchange.ts b/packages/discovery/src/peer-exchange/waku_peer_exchange.ts index babb6bf688..078094cf9d 100644 --- a/packages/discovery/src/peer-exchange/waku_peer_exchange.ts +++ b/packages/discovery/src/peer-exchange/waku_peer_exchange.ts @@ -4,7 +4,7 @@ import { IPeerExchange, Libp2pComponents, PeerExchangeQueryParams, - PeerExchangeResult, + PeerExchangeQueryResult, ProtocolError, PubsubTopic } from "@waku/interfaces"; @@ -35,7 +35,9 @@ export class WakuPeerExchange extends BaseProtocol implements IPeerExchange { /** * Make a peer exchange query to a peer */ - async query(params: PeerExchangeQueryParams): Promise { + async query( + params: PeerExchangeQueryParams + ): Promise { const { numPeers } = params; const rpcQuery = PeerExchangeRPC.createRequest({ numPeers: BigInt(numPeers) diff --git a/packages/discovery/src/peer-exchange/waku_peer_exchange_discovery.ts b/packages/discovery/src/peer-exchange/waku_peer_exchange_discovery.ts index bbf3ca6ff6..5b52340d05 100644 --- a/packages/discovery/src/peer-exchange/waku_peer_exchange_discovery.ts +++ b/packages/discovery/src/peer-exchange/waku_peer_exchange_discovery.ts @@ -8,8 +8,8 @@ import type { PeerInfo } from "@libp2p/interface"; import { - Libp2pComponents, - PeerExchangeResult, + type Libp2pComponents, + type PeerExchangeQueryResult, PubsubTopic, Tags } from "@waku/interfaces"; @@ -165,7 +165,7 @@ export class PeerExchangeDiscovery }, queryInterval * currentAttempt); }; - private async query(peerId: PeerId): Promise { + private async query(peerId: PeerId): Promise { const { error, peerInfos } = await this.peerExchange.query({ numPeers: DEFAULT_PEER_EXCHANGE_REQUEST_NODES, peerId diff --git a/packages/relay/src/index.ts b/packages/relay/src/index.ts index bbe10447b9..c1f0addc10 100644 --- a/packages/relay/src/index.ts +++ b/packages/relay/src/index.ts @@ -22,7 +22,7 @@ import { ProtocolCreateOptions, ProtocolError, PubsubTopic, - SendResult + SDKProtocolResult } from "@waku/interfaces"; import { isWireSizeUnderCap, toAsyncIterator } from "@waku/utils"; import { pushOrInitMapSet } from "@waku/utils"; @@ -99,7 +99,10 @@ class Relay implements IRelay { /** * Send Waku message. */ - public async send(encoder: IEncoder, message: IMessage): Promise { + public async send( + encoder: IEncoder, + message: IMessage + ): Promise { const successes: PeerId[] = []; const { pubsubTopic } = encoder; @@ -142,7 +145,8 @@ class Relay implements IRelay { const { recipients } = await this.gossipSub.publish(pubsubTopic, msg); return { - successes: recipients + successes: recipients, + failures: [] }; } diff --git a/packages/sdk/src/utils/content_topic.ts b/packages/sdk/src/utils/content_topic.ts index dd09940641..68c5eeb320 100644 --- a/packages/sdk/src/utils/content_topic.ts +++ b/packages/sdk/src/utils/content_topic.ts @@ -3,7 +3,7 @@ import { createDecoder, DecodedMessage, waitForRemotePeer } from "@waku/core"; import { Callback, IDecoder, - IFilterSubscriptionSDK, + ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; @@ -27,7 +27,7 @@ async function prepareSubscription( peer: Multiaddr ): Promise<{ decoder: IDecoder; - subscription: IFilterSubscriptionSDK; + subscription: ISubscriptionSDK; }> { // Validate that the Waku node matches assumptions if (!waku.filter) { @@ -52,7 +52,10 @@ async function prepareSubscription( // Create decoder and subscription let decoder = createDecoder(contentTopic, pubsubTopic); if (decoder) decoder = decoder ?? decoder; - const subscription = await waku.filter.createSubscription(pubsubTopic); + const { subscription, error } = + await waku.filter.createSubscription(pubsubTopic); + if (error) + throw new Error("Failed to create subscription for content topic."); return { decoder, subscription }; } @@ -106,7 +109,7 @@ export async function subscribeToContentTopic( contentTopic: string, callback: Callback, opts: CreateTopicOptions -): Promise<{ subscription: IFilterSubscriptionSDK; waku: LightNode }> { +): Promise<{ subscription: ISubscriptionSDK; waku: LightNode }> { opts.waku = opts.waku ?? (await createLightNode({ diff --git a/packages/sdk/src/waku.ts b/packages/sdk/src/waku.ts index ed4f4363f8..fd22270530 100644 --- a/packages/sdk/src/waku.ts +++ b/packages/sdk/src/waku.ts @@ -5,10 +5,10 @@ import { ConnectionManager, DecodedMessage } from "@waku/core"; import type { Callback, IFilterSDK, - IFilterSubscriptionSDK, ILightPushSDK, IRelay, IStoreSDK, + ISubscriptionSDK, Libp2p, LightNode, ProtocolCreateOptions, @@ -192,7 +192,7 @@ export class WakuNode implements Waku { contentTopic: string, peer: Multiaddr, callback: Callback - ): Promise { + ): Promise { return ( await subscribeToContentTopic(contentTopic, callback, { waku: this as LightNode, From cf9fda234053714e1c25f3686d2625e5badd0c48 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 23 Apr 2024 18:07:52 +0530 Subject: [PATCH 08/18] chore: update all tests --- packages/tests/tests/ephemeral.node.spec.ts | 8 +- packages/tests/tests/filter/ping.node.spec.ts | 8 +- packages/tests/tests/filter/push.node.spec.ts | 12 ++- .../single_node/multiple_pubsub.node.spec.ts | 102 ++++++++++++------ .../filter/single_node/ping.node.spec.ts | 8 +- .../filter/single_node/push.node.spec.ts | 13 ++- .../filter/single_node/subscribe.node.spec.ts | 24 +++-- .../single_node/unsubscribe.node.spec.ts | 8 +- .../tests/tests/filter/subscribe.node.spec.ts | 17 ++- .../tests/filter/unsubscribe.node.spec.ts | 11 +- packages/tests/tests/filter/utils.ts | 4 +- .../tests/tests/peer-exchange/query.spec.ts | 6 +- 12 files changed, 149 insertions(+), 72 deletions(-) diff --git a/packages/tests/tests/ephemeral.node.spec.ts b/packages/tests/tests/ephemeral.node.spec.ts index fe0d5b075b..3d7d7c69f4 100644 --- a/packages/tests/tests/ephemeral.node.spec.ts +++ b/packages/tests/tests/ephemeral.node.spec.ts @@ -4,7 +4,7 @@ import { DecodedMessage, waitForRemotePeer } from "@waku/core"; -import { IFilterSubscription, Protocols } from "@waku/interfaces"; +import { ISubscriptionSDK, Protocols } from "@waku/interfaces"; import type { LightNode } from "@waku/interfaces"; import { generatePrivateKey, @@ -47,7 +47,7 @@ describe("Waku Message Ephemeral field", function () { let waku: LightNode; let nwaku: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; afterEachCustom(this, async () => { await tearDownNodes(nwaku, waku); @@ -74,7 +74,9 @@ describe("Waku Message Ephemeral field", function () { Protocols.Store ]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; }); it("Ephemeral messages are not stored", async function () { diff --git a/packages/tests/tests/filter/ping.node.spec.ts b/packages/tests/tests/filter/ping.node.spec.ts index 4604bd5d2b..75f38d5361 100644 --- a/packages/tests/tests/filter/ping.node.spec.ts +++ b/packages/tests/tests/filter/ping.node.spec.ts @@ -1,6 +1,6 @@ import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; @@ -27,13 +27,15 @@ const runTests = (strictCheckNodes: boolean): void => { this.timeout(10000); let waku: LightNode; let serviceNodes: ServiceNodesFleet; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ DefaultPubsubTopic ]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; }); afterEachCustom(this, async () => { diff --git a/packages/tests/tests/filter/push.node.spec.ts b/packages/tests/tests/filter/push.node.spec.ts index 67a862071e..0c641f52e5 100644 --- a/packages/tests/tests/filter/push.node.spec.ts +++ b/packages/tests/tests/filter/push.node.spec.ts @@ -1,7 +1,7 @@ import { waitForRemotePeer } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; @@ -32,13 +32,15 @@ const runTests = (strictCheckNodes: boolean): void => { this.timeout(10000); let waku: LightNode; let serviceNodes: ServiceNodesFleet; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ DefaultPubsubTopic ]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; }); afterEachCustom(this, async () => { @@ -239,7 +241,9 @@ const runTests = (strictCheckNodes: boolean): void => { await waku.dial(await node.getMultiaddrWithId()); await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); } - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; await subscription.subscribe( [TestDecoder], serviceNodes.messageCollector.callback diff --git a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts index 55f176434c..ce5399b1bd 100644 --- a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts @@ -1,7 +1,7 @@ import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; import type { ContentTopicInfo, - IFilterSubscription, + ISubscriptionSDK, LightNode, ShardInfo, SingleShardInfo @@ -35,7 +35,7 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { let waku: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; const customPubsubTopic1 = singleShardInfoToPubsubTopic({ @@ -68,9 +68,13 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { [customPubsubTopic1, customPubsubTopic2], shardInfo ); - subscription = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic1) - ); + + const { error, subscription: _subscription } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(customPubsubTopic1) + ); + if (!error) subscription = _subscription; + messageCollector = new MessageCollector(); }); @@ -93,9 +97,13 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { await subscription.subscribe([customDecoder1], messageCollector.callback); // Subscribe from the same lightnode to the 2nd pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2) - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(customPubsubTopic2) + ); + if (error) { + throw error; + } const messageCollector2 = new MessageCollector(); @@ -136,10 +144,16 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2), - await nwaku2.getPeerId() - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(customPubsubTopic2), + await nwaku2.getPeerId() + ); + + if (error) { + throw error; + } + await nwaku2.ensureSubscriptions([customPubsubTopic2]); const messageCollector2 = new MessageCollector(); @@ -192,7 +206,7 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { let waku: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; const customContentTopic1 = "/waku/2/content/utf8"; @@ -244,9 +258,11 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { [autoshardingPubsubTopic1, autoshardingPubsubTopic2], contentTopicInfo ); - subscription = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic1) - ); + const { error, subscription: _subscription } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(autoshardingPubsubTopic1) + ); + if (!error) subscription = _subscription; messageCollector = new MessageCollector(); }); @@ -273,9 +289,14 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { await subscription.subscribe([customDecoder1], messageCollector.callback); // Subscribe from the same lightnode to the 2nd pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2) - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2) + ); + + if (error) { + throw error; + } const messageCollector2 = new MessageCollector(); @@ -325,10 +346,16 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2), - await nwaku2.getPeerId() - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2), + await nwaku2.getPeerId() + ); + + if (error) { + throw error; + } + await nwaku2.ensureSubscriptionsAutosharding([customContentTopic2]); const messageCollector2 = new MessageCollector(); @@ -380,7 +407,7 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { let waku: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; const customPubsubTopic1 = singleShardInfoToPubsubTopic({ @@ -413,7 +440,10 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { shards: [1, 2] } ); - subscription = await waku.filter.createSubscription(customPubsubTopic1); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(customPubsubTopic1); + if (!error) subscription = _subscription; + messageCollector = new MessageCollector(); }); @@ -436,9 +466,13 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { await subscription.subscribe([customDecoder1], messageCollector.callback); // Subscribe from the same lightnode to the 2nd pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2) - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(customPubsubTopic2) + ); + if (error) { + throw error; + } const messageCollector2 = new MessageCollector(); @@ -479,10 +513,14 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic - const subscription2 = await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2), - await nwaku2.getPeerId() - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription( + pubsubTopicToSingleShardInfo(customPubsubTopic2), + await nwaku2.getPeerId() + ); + if (error) { + throw error; + } await nwaku2.ensureSubscriptions([customPubsubTopic2]); const messageCollector2 = new MessageCollector(); diff --git a/packages/tests/tests/filter/single_node/ping.node.spec.ts b/packages/tests/tests/filter/single_node/ping.node.spec.ts index 14f9bf0b4f..5fe775b98e 100644 --- a/packages/tests/tests/filter/single_node/ping.node.spec.ts +++ b/packages/tests/tests/filter/single_node/ping.node.spec.ts @@ -1,6 +1,6 @@ import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; @@ -27,12 +27,14 @@ describe("Waku Filter V2: Ping", function () { this.timeout(10000); let waku: LightNode; let nwaku: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; beforeEachCustom(this, async () => { [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; messageCollector = new MessageCollector(); }); diff --git a/packages/tests/tests/filter/single_node/push.node.spec.ts b/packages/tests/tests/filter/single_node/push.node.spec.ts index e905a0fdd0..8cab2e1d8c 100644 --- a/packages/tests/tests/filter/single_node/push.node.spec.ts +++ b/packages/tests/tests/filter/single_node/push.node.spec.ts @@ -1,7 +1,7 @@ import { waitForRemotePeer } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; @@ -31,12 +31,15 @@ describe("Waku Filter V2: FilterPush", function () { this.timeout(10000); let waku: LightNode; let nwaku: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; beforeEachCustom(this, async () => { [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; + messageCollector = new MessageCollector(); }); @@ -222,7 +225,9 @@ describe("Waku Filter V2: FilterPush", function () { // Redo the connection and create a new subscription await waku.dial(await nwaku.getMultiaddrWithId()); await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; await subscription.subscribe([TestDecoder], messageCollector.callback); await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M2") }); diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index fa53c19608..523968dc1f 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -1,7 +1,7 @@ import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; @@ -43,12 +43,15 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { let waku: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; beforeEachCustom(this, async () => { [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; + messageCollector = new MessageCollector(); await nwaku.ensureSubscriptions(); }); @@ -439,7 +442,11 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M1") }); // Create a second subscription on a different topic - const subscription2 = await waku.filter.createSubscription(); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription(); + if (error) { + throw error; + } const newContentTopic = "/test/2/waku-filter"; const newEncoder = createEncoder({ contentTopic: newContentTopic }); const newDecoder = createDecoder(newContentTopic); @@ -471,10 +478,11 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { }); await waku.dial(await nwaku2.getMultiaddrWithId()); await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); - const subscription2 = await waku.filter.createSubscription( - undefined, - await nwaku2.getPeerId() - ); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription(undefined, await nwaku2.getPeerId()); + if (error) { + throw error; + } await nwaku2.ensureSubscriptions([DefaultPubsubTopic]); // Send a message using the new subscription const newContentTopic = "/test/2/waku-filter"; diff --git a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts index c0c95c6258..1607af2107 100644 --- a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts @@ -1,5 +1,5 @@ import { createDecoder, createEncoder } from "@waku/core"; -import { DefaultPubsubTopic, IFilterSubscription } from "@waku/interfaces"; +import { DefaultPubsubTopic, ISubscriptionSDK } from "@waku/interfaces"; import { LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -26,12 +26,14 @@ describe("Waku Filter V2: Unsubscribe", function () { this.timeout(10000); let waku: LightNode; let nwaku: ServiceNode; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; beforeEachCustom(this, async () => { [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + if (!error) subscription = _subscription; messageCollector = new MessageCollector(); // Nwaku subscribe to the default pubsub topic diff --git a/packages/tests/tests/filter/subscribe.node.spec.ts b/packages/tests/tests/filter/subscribe.node.spec.ts index 422d11e096..2cddaa020d 100644 --- a/packages/tests/tests/filter/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/subscribe.node.spec.ts @@ -1,7 +1,7 @@ import { createDecoder, createEncoder } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { @@ -39,7 +39,7 @@ const runTests = (strictCheckNodes: boolean): void => { this.timeout(100000); let waku: LightNode; let serviceNodes: ServiceNodesFleet; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes( @@ -47,7 +47,12 @@ const runTests = (strictCheckNodes: boolean): void => { [DefaultPubsubTopic], strictCheckNodes ); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + + if (!error) { + subscription = _subscription; + } }); afterEachCustom(this, async () => { @@ -522,7 +527,11 @@ const runTests = (strictCheckNodes: boolean): void => { await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M1") }); // Create a second subscription on a different topic - const subscription2 = await waku.filter.createSubscription(); + const { error, subscription: subscription2 } = + await waku.filter.createSubscription(); + if (error) { + throw error; + } const newContentTopic = "/test/2/waku-filter"; const newEncoder = createEncoder({ contentTopic: newContentTopic }); const newDecoder = createDecoder(newContentTopic); diff --git a/packages/tests/tests/filter/unsubscribe.node.spec.ts b/packages/tests/tests/filter/unsubscribe.node.spec.ts index dffacf3a1b..7b7d0ad3f9 100644 --- a/packages/tests/tests/filter/unsubscribe.node.spec.ts +++ b/packages/tests/tests/filter/unsubscribe.node.spec.ts @@ -1,7 +1,7 @@ import { createDecoder, createEncoder } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; @@ -30,13 +30,18 @@ const runTests = (strictCheckNodes: boolean): void => { this.timeout(10000); let waku: LightNode; let serviceNodes: ServiceNodesFleet; - let subscription: IFilterSubscription; + let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ DefaultPubsubTopic ]); - subscription = await waku.filter.createSubscription(); + const { error, subscription: _subscription } = + await waku.filter.createSubscription(); + + if (!error) { + subscription = _subscription; + } }); afterEachCustom(this, async () => { diff --git a/packages/tests/tests/filter/utils.ts b/packages/tests/tests/filter/utils.ts index d7aec2fab9..1f269c94c1 100644 --- a/packages/tests/tests/filter/utils.ts +++ b/packages/tests/tests/filter/utils.ts @@ -1,7 +1,7 @@ import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; import { DefaultPubsubTopic, - IFilterSubscription, + ISubscriptionSDK, LightNode, ProtocolCreateOptions, Protocols, @@ -34,7 +34,7 @@ export const messagePayload = { payload: utf8ToBytes(messageText) }; // Utility to validate errors related to pings in the subscription. export async function validatePingError( - subscription: IFilterSubscription + subscription: ISubscriptionSDK ): Promise { try { await subscription.ping(); diff --git a/packages/tests/tests/peer-exchange/query.spec.ts b/packages/tests/tests/peer-exchange/query.spec.ts index 9ebb832af5..8dd70aad28 100644 --- a/packages/tests/tests/peer-exchange/query.spec.ts +++ b/packages/tests/tests/peer-exchange/query.spec.ts @@ -7,7 +7,7 @@ import { WakuPeerExchange, wakuPeerExchangeDiscovery } from "@waku/discovery"; -import type { LightNode, PeerExchangeResult } from "@waku/interfaces"; +import type { LightNode, PeerExchangeQueryResult } from "@waku/interfaces"; import { createLightNode, Libp2pComponents, ProtocolError } from "@waku/sdk"; import { Logger, singleShardInfoToPubsubTopic } from "@waku/utils"; import { expect } from "chai"; @@ -38,7 +38,7 @@ describe("Peer Exchange Query", function () { let components: Libp2pComponents; let peerExchange: WakuPeerExchange; let numPeersToRequest: number; - let queryResult: PeerExchangeResult; + let queryResult: PeerExchangeQueryResult; beforeEachCustom( this, @@ -99,7 +99,7 @@ describe("Peer Exchange Query", function () { peerId: nwaku3PeerId, numPeers: numPeersToRequest }), - new Promise((resolve) => + new Promise((resolve) => setTimeout( () => resolve({ From 318bbfddb755e869425afacb248cf8be49afc18a Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 29 Apr 2024 19:53:04 +0530 Subject: [PATCH 09/18] chore: resolve conflicts & merge (2/n) --- packages/tests/src/lib/index.ts | 5 +- packages/tests/src/lib/message_collector.ts | 15 +- packages/tests/src/lib/runNodes.ts | 78 ++++++ packages/tests/src/lib/service_node.ts | 19 +- .../tests/src/utils/generate_test_data.ts | 17 +- .../tests/src/utils/waku_versions_utils.ts | 17 -- .../connection_state.spec.ts | 4 +- packages/tests/tests/ephemeral.node.spec.ts | 202 ++++++++------- packages/tests/tests/filter/ping.node.spec.ts | 13 +- packages/tests/tests/filter/push.node.spec.ts | 58 +++-- .../single_node/multiple_pubsub.node.spec.ts | 77 ++---- .../filter/single_node/ping.node.spec.ts | 12 +- .../filter/single_node/push.node.spec.ts | 28 +-- .../filter/single_node/subscribe.node.spec.ts | 235 +++++++----------- .../single_node/unsubscribe.node.spec.ts | 38 +-- .../tests/tests/filter/single_node/utils.ts | 76 +----- .../tests/tests/filter/subscribe.node.spec.ts | 210 ++++++---------- .../tests/filter/unsubscribe.node.spec.ts | 38 +-- packages/tests/tests/filter/utils.ts | 35 +-- packages/tests/tests/getPeers.spec.ts | 15 +- .../tests/tests/light-push/index.node.spec.ts | 129 ++++++---- packages/tests/tests/metadata.spec.ts | 4 +- packages/tests/tests/utils.spec.ts | 43 ++-- .../tests/wait_for_remote_peer.node.spec.ts | 42 +--- 24 files changed, 670 insertions(+), 740 deletions(-) create mode 100644 packages/tests/src/lib/runNodes.ts diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index 5bcc9c947c..924febf82a 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -2,7 +2,6 @@ import { DecodedMessage } from "@waku/core"; import { DefaultPubsubTopic, PubsubTopic, - ShardInfo, ShardingParams } from "@waku/interfaces"; import { ensureShardingConfigured, Logger } from "@waku/utils"; @@ -12,9 +11,11 @@ import { Args, MessageRpcQuery, MessageRpcResponse } from "../types"; import { delay, makeLogFileName } from "../utils/index.js"; import { MessageCollector } from "./message_collector.js"; +import { runNodes } from "./runNodes.js"; import { defaultArgs, ServiceNode } from "./service_node.js"; export { ServiceNode, MessageCollector, defaultArgs }; +export { runNodes }; const log = new Logger("test:message-collector"); @@ -28,7 +29,7 @@ export class ServiceNodesFleet { pubsubTopics: PubsubTopic[], nodesToCreate: number = 3, strictChecking: boolean = false, - shardInfo?: ShardInfo, + shardInfo?: ShardingParams, _args?: Args, withoutFilter = false ): Promise { diff --git a/packages/tests/src/lib/message_collector.ts b/packages/tests/src/lib/message_collector.ts index b8d1b408c6..154c0b7284 100644 --- a/packages/tests/src/lib/message_collector.ts +++ b/packages/tests/src/lib/message_collector.ts @@ -73,7 +73,7 @@ export class MessageCollector { } ): Promise { const startTime = Date.now(); - const pubsubTopic = options?.pubsubTopic || DefaultPubsubTopic; + const pubsubTopic = this.getPubsubTopicToUse(options?.pubsubTopic); const timeoutDuration = options?.timeoutDuration || 400; const exact = options?.exact || false; @@ -237,12 +237,13 @@ export class MessageCollector { `Message text mismatch. Expected: ${options.expectedMessageText}. Got: ${receivedMessageText}` ); } else { + const pubsubTopicToUse = this.getPubsubTopicToUse( + options.expectedPubsubTopic + ); // js-waku message specific assertions expect(message.pubsubTopic).to.eq( - options.expectedPubsubTopic || DefaultPubsubTopic, - `Message pub/sub topic mismatch. Expected: ${ - options.expectedPubsubTopic || DefaultPubsubTopic - }. Got: ${message.pubsubTopic}` + pubsubTopicToUse, + `Message pub/sub topic mismatch. Expected: ${pubsubTopicToUse}. Got: ${message.pubsubTopic}` ); expect(bytesToUtf8(message.payload)).to.eq( @@ -266,4 +267,8 @@ export class MessageCollector { ); } } + + private getPubsubTopicToUse(pubsubTopic: string | undefined): string { + return pubsubTopic || this.nwaku?.pubsubTopics?.[0] || DefaultPubsubTopic; + } } diff --git a/packages/tests/src/lib/runNodes.ts b/packages/tests/src/lib/runNodes.ts new file mode 100644 index 0000000000..908b4e274d --- /dev/null +++ b/packages/tests/src/lib/runNodes.ts @@ -0,0 +1,78 @@ +import { waitForRemotePeer } from "@waku/core"; +import { + ContentTopicInfo, + ProtocolCreateOptions, + Protocols, + ShardingParams +} from "@waku/interfaces"; +import { createLightNode, WakuNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; +import { Logger, shardInfoToPubsubTopics } from "@waku/utils"; +import { Context } from "mocha"; + +import { NOISE_KEY_1 } from "../constants.js"; +import { makeLogFileName } from "../utils/index.js"; + +import { ServiceNode } from "./service_node.js"; + +export const log = new Logger("test:runNodes"); + +type RunNodesOptions = { + context: Context; + shardInfo: ShardingParams; + protocols: Protocols[]; + createNode: typeof createLightNode | typeof createRelayNode; +}; + +export async function runNodes( + options: RunNodesOptions +): Promise<[ServiceNode, T]> { + const { context, shardInfo, createNode, protocols } = options; + + const nwaku = new ServiceNode(makeLogFileName(context)); + const pubsubTopics = shardInfoToPubsubTopics(shardInfo); + + function isContentTopicInfo(info: ShardingParams): info is ContentTopicInfo { + return (info as ContentTopicInfo).contentTopics !== undefined; + } + + await nwaku.start( + { + filter: true, + lightpush: true, + relay: true, + store: true, + pubsubTopic: pubsubTopics, + // Conditionally include clusterId if shardInfo exists + ...(shardInfo && { clusterId: shardInfo.clusterId }), + // Conditionally include contentTopic if shardInfo exists and clusterId is 1 + ...(shardInfo && + isContentTopicInfo(shardInfo) && + shardInfo.clusterId === 1 && { contentTopic: shardInfo.contentTopics }) + }, + { retries: 3 } + ); + const waku_options: ProtocolCreateOptions = { + staticNoiseKey: NOISE_KEY_1, + libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } }, + shardInfo + }; + + log.info("Starting js waku node with :", JSON.stringify(waku_options)); + let waku: WakuNode | undefined; + try { + waku = (await createNode(waku_options)) as WakuNode; + await waku.start(); + } catch (error) { + log.error("jswaku node failed to start:", error); + } + + if (waku) { + await waku.dial(await nwaku.getMultiaddrWithId()); + await waitForRemotePeer(waku, protocols); + await nwaku.ensureSubscriptions(pubsubTopics); + return [nwaku, waku as T]; + } else { + throw new Error("Failed to initialize waku"); + } +} diff --git a/packages/tests/src/lib/service_node.ts b/packages/tests/src/lib/service_node.ts index 29ea61c5cc..db9b620ee6 100644 --- a/packages/tests/src/lib/service_node.ts +++ b/packages/tests/src/lib/service_node.ts @@ -27,7 +27,7 @@ const WAKU_SERVICE_NODE_PARAMS = const NODE_READY_LOG_LINE = "Node setup complete"; export const DOCKER_IMAGE_NAME = - process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.26.0"; + process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.27.0"; const isGoWaku = DOCKER_IMAGE_NAME.includes("go-waku"); @@ -48,6 +48,7 @@ export class ServiceNode { private websocketPort?: number; private readonly logPath: string; private restPort?: number; + private args?: Args; /** * Convert a [[WakuMessage]] to a [[WakuRelayMessage]]. The latter is used @@ -166,6 +167,8 @@ export class ServiceNode { this.logPath, WAKU_SERVICE_NODE_PARAMS ); + + this.args = mergedArgs; } catch (error) { log.error("Nwaku node failed to start:", error); await this.stop(); @@ -237,11 +240,9 @@ export class ServiceNode { ); } - async messages( - pubsubTopic: string = DefaultPubsubTopic - ): Promise { + async messages(pubsubTopic?: string): Promise { return this.restCall( - `/relay/v1/messages/${encodeURIComponent(pubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(pubsubTopic || this?.args?.pubsubTopic?.[0] || DefaultPubsubTopic)}`, "GET", null, async (response) => { @@ -266,7 +267,7 @@ export class ServiceNode { async sendMessage( message: MessageRpcQuery, - pubsubTopic: string = DefaultPubsubTopic + pubsubTopic?: string ): Promise { this.checkProcess(); @@ -275,7 +276,7 @@ export class ServiceNode { } return this.restCall( - `/relay/v1/messages/${encodeURIComponent(pubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(pubsubTopic || this.args?.pubsubTopic?.[0] || DefaultPubsubTopic)}`, "POST", message, async (response) => response.status === 200 @@ -350,6 +351,10 @@ export class ServiceNode { return `http://127.0.0.1:${this.restPort}`; } + get pubsubTopics(): string[] { + return this.args?.pubsubTopic ?? []; + } + async restCall( endpoint: string, method: "GET" | "POST", diff --git a/packages/tests/src/utils/generate_test_data.ts b/packages/tests/src/utils/generate_test_data.ts index 8644e26437..cd1b6ed61b 100644 --- a/packages/tests/src/utils/generate_test_data.ts +++ b/packages/tests/src/utils/generate_test_data.ts @@ -1,19 +1,28 @@ import { createDecoder, createEncoder, Decoder, Encoder } from "@waku/core"; +type TestDataOptions = { + pubsubTopic: string; +}; + // Utility to generate test data for multiple topics tests. -export function generateTestData(topicCount: number): { +export function generateTestData( + topicCount: number, + options?: TestDataOptions +): { contentTopics: string[]; encoders: Encoder[]; decoders: Decoder[]; } { const contentTopics = Array.from( { length: topicCount }, - (_, i) => `/test/${i + 1}/waku-multi` + (_, i) => `/test/${i + 1}/waku-multi/default` ); const encoders = contentTopics.map((topic) => - createEncoder({ contentTopic: topic }) + createEncoder({ contentTopic: topic, pubsubTopic: options?.pubsubTopic }) + ); + const decoders = contentTopics.map((topic) => + createDecoder(topic, options?.pubsubTopic) ); - const decoders = contentTopics.map((topic) => createDecoder(topic)); return { contentTopics, encoders, diff --git a/packages/tests/src/utils/waku_versions_utils.ts b/packages/tests/src/utils/waku_versions_utils.ts index e2f6cf5c9c..17bdbf2090 100644 --- a/packages/tests/src/utils/waku_versions_utils.ts +++ b/packages/tests/src/utils/waku_versions_utils.ts @@ -1,9 +1,5 @@ -import { Logger } from "@waku/utils"; - import { DOCKER_IMAGE_NAME } from "../lib/service_node"; -const log = new Logger("test:utils"); - // Utility to add test conditions based on nwaku/go-waku versions export function isNwakuAtLeast(requiredVersion: string): boolean { const versionRegex = /(?:v)?(\d+\.\d+(?:\.\d+)?)/; @@ -19,16 +15,3 @@ export function isNwakuAtLeast(requiredVersion: string): boolean { return true; } } - -// Utility to resolve autosharding cluster ID -export function resolveAutoshardingCluster(clusterId: number): number { - if (isNwakuAtLeast("0.27.0")) { - log.info(`Using clusterID ${clusterId} for autosharding`); - return clusterId; - } else { - // for versions older than 0.27.0 the autosharding cluster was hardcoded to 1 - // https://github.com/waku-org/nwaku/pull/2505 - log.warn("Falling back to clusterID 1 for autosharding"); - return 1; - } -} diff --git a/packages/tests/tests/connection-mananger/connection_state.spec.ts b/packages/tests/tests/connection-mananger/connection_state.spec.ts index 0fd8394ab9..a4e3ba640e 100644 --- a/packages/tests/tests/connection-mananger/connection_state.spec.ts +++ b/packages/tests/tests/connection-mananger/connection_state.spec.ts @@ -87,7 +87,7 @@ describe("Connection state", function () { expect(eventCount).to.be.eq(1); }); - it("`waku:online` bwtween 2 js-waku relay nodes", async function () { + it("`waku:online` between 2 js-waku relay nodes", async function () { const waku1 = await createRelayNode({ staticNoiseKey: NOISE_KEY_1 }); @@ -159,7 +159,7 @@ describe("Connection state", function () { expect(waku.isConnected()).to.be.false; }); - it("isConnected bwtween 2 js-waku relay nodes", async function () { + it("isConnected between 2 js-waku relay nodes", async function () { const waku1 = await createRelayNode({ staticNoiseKey: NOISE_KEY_1 }); diff --git a/packages/tests/tests/ephemeral.node.spec.ts b/packages/tests/tests/ephemeral.node.spec.ts index 3d7d7c69f4..35b6850f6e 100644 --- a/packages/tests/tests/ephemeral.node.spec.ts +++ b/packages/tests/tests/ephemeral.node.spec.ts @@ -12,15 +12,15 @@ import { getPublicKey } from "@waku/message-encryption"; import { - createDecoder as eciesDecoder, - createEncoder as eciesEncoder + createDecoder as createEciesDecoder, + createEncoder as createEciesEncoder } from "@waku/message-encryption/ecies"; import { - createDecoder as symDecoder, - createEncoder as symEncoder + createDecoder as createSymDecoder, + createEncoder as createSymEncoder } from "@waku/message-encryption/symmetric"; import { createLightNode } from "@waku/sdk"; -import { Logger } from "@waku/utils"; +import { contentTopicToPubsubTopic, Logger } from "@waku/utils"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; @@ -37,11 +37,47 @@ import { const log = new Logger("test:ephemeral"); +const ClusterId = 2; const TestContentTopic = "/test/1/ephemeral/utf8"; +const PubsubTopic = contentTopicToPubsubTopic(TestContentTopic, ClusterId); + const TestEncoder = createEncoder({ - contentTopic: TestContentTopic + contentTopic: TestContentTopic, + pubsubTopic: PubsubTopic +}); +const TestDecoder = createDecoder(TestContentTopic, PubsubTopic); + +const privateKey = generatePrivateKey(); +const symKey = generateSymmetricKey(); +const publicKey = getPublicKey(privateKey); + +const AsymContentTopic = "/test/1/ephemeral-asym/utf8"; +const SymContentTopic = "/test/1/ephemeral-sym/utf8"; + +const AsymEncoder = createEciesEncoder({ + contentTopic: AsymContentTopic, + publicKey, + ephemeral: true, + pubsubTopic: PubsubTopic +}); +const SymEncoder = createSymEncoder({ + contentTopic: SymContentTopic, + symKey, + ephemeral: true, + pubsubTopic: PubsubTopic +}); +const ClearEncoder = createEncoder({ + contentTopic: TestContentTopic, + ephemeral: true, + pubsubTopic: PubsubTopic }); -const TestDecoder = createDecoder(TestContentTopic); + +const AsymDecoder = createEciesDecoder( + AsymContentTopic, + privateKey, + PubsubTopic +); +const SymDecoder = createSymDecoder(SymContentTopic, symKey, PubsubTopic); describe("Waku Message Ephemeral field", function () { let waku: LightNode; @@ -59,11 +95,24 @@ describe("Waku Message Ephemeral field", function () { filter: true, lightpush: true, store: true, - relay: true + relay: true, + pubsubTopic: [PubsubTopic], + contentTopic: [TestContentTopic, AsymContentTopic, SymContentTopic], + clusterId: ClusterId }); + await nwaku.ensureSubscriptionsAutosharding([ + TestContentTopic, + AsymContentTopic, + SymContentTopic + ]); + waku = await createLightNode({ staticNoiseKey: NOISE_KEY_1, - libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } } + libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } }, + shardInfo: { + contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic], + clusterId: ClusterId + } }); await waku.start(); await waku.dial(await nwaku.getMultiaddrWithId()); @@ -75,7 +124,7 @@ describe("Waku Message Ephemeral field", function () { ]); const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestEncoder.pubsubTopic); if (!error) subscription = _subscription; }); @@ -96,37 +145,20 @@ describe("Waku Message Ephemeral field", function () { payload: utf8ToBytes(clearText) }; - const privateKey = generatePrivateKey(); - const symKey = generateSymmetricKey(); - const publicKey = getPublicKey(privateKey); - - const AsymContentTopic = "/test/1/ephemeral-asym/utf8"; - const SymContentTopic = "/test/1/ephemeral-sym/utf8"; - - const asymEncoder = eciesEncoder({ - contentTopic: AsymContentTopic, - publicKey, - ephemeral: true - }); - const symEncoder = eciesEncoder({ - contentTopic: SymContentTopic, - publicKey: symKey, - ephemeral: true - }); - const clearEncoder = createEncoder({ - contentTopic: TestContentTopic, - ephemeral: true - }); - - const asymDecoder = eciesDecoder(AsymContentTopic, privateKey); - const symDecoder = eciesDecoder(SymContentTopic, symKey); - const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([ createLightNode({ - staticNoiseKey: NOISE_KEY_1 + staticNoiseKey: NOISE_KEY_1, + shardInfo: { + contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic], + clusterId: ClusterId + } }).then((waku) => waku.start().then(() => waku)), createLightNode({ - staticNoiseKey: NOISE_KEY_2 + staticNoiseKey: NOISE_KEY_2, + shardInfo: { + contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic], + clusterId: ClusterId + } }).then((waku) => waku.start().then(() => waku)), nwaku.getMultiaddrWithId() ]); @@ -144,9 +176,9 @@ describe("Waku Message Ephemeral field", function () { log.info("Sending messages using light push"); await Promise.all([ - waku1.lightPush.send(asymEncoder, asymMsg), - waku1.lightPush.send(symEncoder, symMsg), - waku1.lightPush.send(clearEncoder, clearMsg) + waku1.lightPush.send(AsymEncoder, asymMsg), + waku1.lightPush.send(SymEncoder, symMsg), + waku1.lightPush.send(ClearEncoder, clearMsg) ]); await waitForRemotePeer(waku2, [Protocols.Store]); @@ -155,8 +187,8 @@ describe("Waku Message Ephemeral field", function () { log.info("Retrieving messages from store"); for await (const msgPromises of waku2.store.queryGenerator([ - asymDecoder, - symDecoder, + AsymDecoder, + SymDecoder, TestDecoder ])) { for (const promise of msgPromises) { @@ -177,7 +209,8 @@ describe("Waku Message Ephemeral field", function () { const ephemeralEncoder = createEncoder({ contentTopic: TestContentTopic, - ephemeral: true + ephemeral: true, + pubsubTopic: PubsubTopic }); const messages: DecodedMessage[] = []; @@ -189,12 +222,16 @@ describe("Waku Message Ephemeral field", function () { await delay(200); const normalTxt = "Normal message"; const ephemeralTxt = "Ephemeral Message"; - await waku.lightPush.send(TestEncoder, { - payload: utf8ToBytes(normalTxt) - }); - await waku.lightPush.send(ephemeralEncoder, { - payload: utf8ToBytes(ephemeralTxt) - }); + + await Promise.all([ + waku.lightPush.send(TestEncoder, { + payload: utf8ToBytes(normalTxt) + }), + waku.lightPush.send(ephemeralEncoder, { + payload: utf8ToBytes(ephemeralTxt) + }) + ]); + while (messages.length < 2) { await delay(250); } @@ -216,18 +253,12 @@ describe("Waku Message Ephemeral field", function () { it("Ephemeral field is preserved - symmetric encryption", async function () { this.timeout(10000); - const symKey = generateSymmetricKey(); - - const ephemeralEncoder = symEncoder({ - contentTopic: TestContentTopic, + const encoder = createSymEncoder({ + contentTopic: SymContentTopic, symKey, - ephemeral: true + pubsubTopic: PubsubTopic }); - const encoder = symEncoder({ - contentTopic: TestContentTopic, - symKey - }); - const decoder = symDecoder(TestContentTopic, symKey); + const decoder = createSymDecoder(SymContentTopic, symKey, PubsubTopic); const messages: DecodedMessage[] = []; const callback = (msg: DecodedMessage): void => { @@ -238,12 +269,16 @@ describe("Waku Message Ephemeral field", function () { await delay(200); const normalTxt = "Normal message"; const ephemeralTxt = "Ephemeral Message"; - await waku.lightPush.send(encoder, { - payload: utf8ToBytes(normalTxt) - }); - await waku.lightPush.send(ephemeralEncoder, { - payload: utf8ToBytes(ephemeralTxt) - }); + + await Promise.all([ + waku.lightPush.send(encoder, { + payload: utf8ToBytes(normalTxt) + }), + waku.lightPush.send(SymEncoder, { + payload: utf8ToBytes(ephemeralTxt) + }) + ]); + while (messages.length < 2) { await delay(250); } @@ -265,19 +300,16 @@ describe("Waku Message Ephemeral field", function () { it("Ephemeral field is preserved - asymmetric encryption", async function () { this.timeout(10000); - const privKey = generatePrivateKey(); - const pubKey = getPublicKey(privKey); - - const ephemeralEncoder = eciesEncoder({ - contentTopic: TestContentTopic, - publicKey: pubKey, - ephemeral: true - }); - const encoder = eciesEncoder({ - contentTopic: TestContentTopic, - publicKey: pubKey + const encoder = createEciesEncoder({ + contentTopic: AsymContentTopic, + publicKey: publicKey, + pubsubTopic: PubsubTopic }); - const decoder = eciesDecoder(TestContentTopic, privKey); + const decoder = createEciesDecoder( + AsymContentTopic, + privateKey, + PubsubTopic + ); const messages: DecodedMessage[] = []; const callback = (msg: DecodedMessage): void => { @@ -288,12 +320,16 @@ describe("Waku Message Ephemeral field", function () { await delay(200); const normalTxt = "Normal message"; const ephemeralTxt = "Ephemeral Message"; - await waku.lightPush.send(encoder, { - payload: utf8ToBytes(normalTxt) - }); - await waku.lightPush.send(ephemeralEncoder, { - payload: utf8ToBytes(ephemeralTxt) - }); + + await Promise.all([ + waku.lightPush.send(encoder, { + payload: utf8ToBytes(normalTxt) + }), + waku.lightPush.send(AsymEncoder, { + payload: utf8ToBytes(ephemeralTxt) + }) + ]); + while (messages.length < 2) { await delay(250); } diff --git a/packages/tests/tests/filter/ping.node.spec.ts b/packages/tests/tests/filter/ping.node.spec.ts index 75f38d5361..d99b659680 100644 --- a/packages/tests/tests/filter/ping.node.spec.ts +++ b/packages/tests/tests/filter/ping.node.spec.ts @@ -1,8 +1,4 @@ -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -18,6 +14,7 @@ import { TestContentTopic, TestDecoder, TestEncoder, + TestShardInfo, validatePingError } from "./utils"; @@ -30,11 +27,9 @@ const runTests = (strictCheckNodes: boolean): void => { let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { - [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ - DefaultPubsubTopic - ]); + [serviceNodes, waku] = await runMultipleNodes(this.ctx, TestShardInfo); const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; }); diff --git a/packages/tests/tests/filter/push.node.spec.ts b/packages/tests/tests/filter/push.node.spec.ts index 0c641f52e5..bf215ceea0 100644 --- a/packages/tests/tests/filter/push.node.spec.ts +++ b/packages/tests/tests/filter/push.node.spec.ts @@ -1,10 +1,5 @@ import { waitForRemotePeer } from "@waku/core"; -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode, - Protocols -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -23,7 +18,9 @@ import { teardownNodesWithRedundancy, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic, + TestShardInfo } from "./utils.js"; const runTests = (strictCheckNodes: boolean): void => { @@ -35,11 +32,10 @@ const runTests = (strictCheckNodes: boolean): void => { let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { - [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ - DefaultPubsubTopic - ]); + [serviceNodes, waku] = await runMultipleNodes(this.ctx, TestShardInfo); + const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; }); @@ -62,7 +58,8 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: testItem.value, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -81,7 +78,7 @@ const runTests = (strictCheckNodes: boolean): void => { payload: Buffer.from(utf8ToBytes(messageText)).toString("base64"), timestamp: testItem as any }, - DefaultPubsubTopic + TestPubsubTopic ); expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( @@ -90,7 +87,8 @@ const runTests = (strictCheckNodes: boolean): void => { serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, checkTimestamp: false, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); // Check if the timestamp matches @@ -119,7 +117,7 @@ const runTests = (strictCheckNodes: boolean): void => { payload: Buffer.from(utf8ToBytes(messageText)).toString("base64"), timestamp: "2023-09-06T12:05:38.609Z" as any }, - DefaultPubsubTopic + TestPubsubTopic ); // Verify that no message was received @@ -141,12 +139,14 @@ const runTests = (strictCheckNodes: boolean): void => { payload: Buffer.from(utf8ToBytes(messageText)).toString("base64"), timestamp: BigInt(Date.now()) * BigInt(1000000) }, - "DefaultPubsubTopic" + "WrongContentTopic" ); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - false - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(false); }); it("Check message with no content topic is not received", async function () { @@ -161,7 +161,7 @@ const runTests = (strictCheckNodes: boolean): void => { payload: Buffer.from(utf8ToBytes(messageText)).toString("base64"), timestamp: BigInt(Date.now()) * BigInt(1000000) }, - DefaultPubsubTopic + TestPubsubTopic ); expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( @@ -182,7 +182,7 @@ const runTests = (strictCheckNodes: boolean): void => { timestamp: BigInt(Date.now()) * BigInt(1000000), payload: undefined as any }, - DefaultPubsubTopic + TestPubsubTopic ); // For go-waku the message is received (it is possible to send a message with no payload) @@ -210,7 +210,7 @@ const runTests = (strictCheckNodes: boolean): void => { payload: 12345 as unknown as string, timestamp: BigInt(Date.now()) * BigInt(1000000) }, - DefaultPubsubTopic + TestPubsubTopic ); expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( @@ -242,7 +242,7 @@ const runTests = (strictCheckNodes: boolean): void => { await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); } const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; await subscription.subscribe( [TestDecoder], @@ -257,11 +257,13 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); @@ -289,11 +291,13 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); diff --git a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts index ce5399b1bd..200ea0824d 100644 --- a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts @@ -10,7 +10,6 @@ import { Protocols } from "@waku/interfaces"; import { contentTopicToPubsubTopic, contentTopicToShardIndex, - pubsubTopicToSingleShardInfo, singleShardInfoToPubsubTopic } from "@waku/utils"; import { utf8ToBytes } from "@waku/utils/bytes"; @@ -19,10 +18,8 @@ import { expect } from "chai"; import { afterEachCustom, beforeEachCustom, - isNwakuAtLeast, makeLogFileName, MessageCollector, - resolveAutoshardingCluster, ServiceNode, tearDownNodes } from "../../../src/index.js"; @@ -63,16 +60,10 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { const customDecoder2 = createDecoder(customContentTopic2, singleShardInfo2); beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes( - this.ctx, - [customPubsubTopic1, customPubsubTopic2], - shardInfo - ); + [nwaku, waku] = await runNodes(this.ctx, shardInfo); const { error, subscription: _subscription } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic1) - ); + await waku.filter.createSubscription(shardInfo); if (!error) subscription = _subscription; messageCollector = new MessageCollector(); @@ -98,9 +89,7 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the 2nd pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2) - ); + await waku.filter.createSubscription(customPubsubTopic2); if (error) { throw error; } @@ -145,10 +134,7 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2), - await nwaku2.getPeerId() - ); + await waku.filter.createSubscription(customPubsubTopic2); if (error) { throw error; @@ -188,7 +174,7 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { }); it("Should fail to subscribe with decoder with wrong pubsubTopic", async function () { - // this subscription object is set up with the `customPubsubTopic` but we're passing it a Decoder with the `DefaultPubsubTopic` + // this subscription object is set up with the `customPubsubTopic1` but we're passing it a Decoder with the `customPubsubTopic2` try { await subscription.subscribe([customDecoder2], messageCollector.callback); } catch (error) { @@ -202,7 +188,7 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { // Set the timeout for all tests in this suite. Can be overwritten at test level this.timeout(30000); - const clusterId = resolveAutoshardingCluster(3); + const clusterId = 3; let waku: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; @@ -246,22 +232,10 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { shard: contentTopicToShardIndex(customContentTopic2) }); - before(async () => { - if (!isNwakuAtLeast("0.27.0")) { - this.ctx.skip(); - } - }); - beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes( - this.ctx, - [autoshardingPubsubTopic1, autoshardingPubsubTopic2], - contentTopicInfo - ); + [nwaku, waku] = await runNodes(this.ctx, contentTopicInfo); const { error, subscription: _subscription } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic1) - ); + await waku.filter.createSubscription(autoshardingPubsubTopic1); if (!error) subscription = _subscription; messageCollector = new MessageCollector(); }); @@ -290,9 +264,7 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the 2nd pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2) - ); + await waku.filter.createSubscription(autoshardingPubsubTopic2); if (error) { throw error; @@ -347,10 +319,7 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(autoshardingPubsubTopic2), - await nwaku2.getPeerId() - ); + await waku.filter.createSubscription(autoshardingPubsubTopic2); if (error) { throw error; @@ -390,7 +359,7 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { }); it("Should fail to subscribe with decoder with wrong pubsubTopic", async function () { - // this subscription object is set up with the `customPubsubTopic` but we're passing it a Decoder with the `DefaultPubsubTopic` + // this subscription object is set up with the `customPubsubTopic1` but we're passing it a Decoder with the `customPubsubTopic2` try { await subscription.subscribe([customDecoder2], messageCollector.callback); } catch (error) { @@ -418,6 +387,10 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { clusterId: 3, shard: 2 }); + const shardInfo = { + clusterId: 3, + shards: [1, 2] + }; const customContentTopic1 = "/test/2/waku-filter"; const customContentTopic2 = "/test/3/waku-filter"; const customEncoder1 = createEncoder({ @@ -432,14 +405,7 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { const customDecoder2 = createDecoder(customContentTopic2, customPubsubTopic2); beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes( - this.ctx, - [customPubsubTopic1, customPubsubTopic2], - { - clusterId: 3, - shards: [1, 2] - } - ); + [nwaku, waku] = await runNodes(this.ctx, shardInfo); const { error, subscription: _subscription } = await waku.filter.createSubscription(customPubsubTopic1); if (!error) subscription = _subscription; @@ -467,9 +433,7 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the 2nd pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2) - ); + await waku.filter.createSubscription(customPubsubTopic2); if (error) { throw error; } @@ -514,10 +478,7 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { // Subscribe from the same lightnode to the new nwaku on the new pubsubtopic const { error, subscription: subscription2 } = - await waku.filter.createSubscription( - pubsubTopicToSingleShardInfo(customPubsubTopic2), - await nwaku2.getPeerId() - ); + await waku.filter.createSubscription(customPubsubTopic2); if (error) { throw error; } @@ -555,7 +516,7 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { }); it("Should fail to subscribe with decoder with wrong pubsubTopic", async function () { - // this subscription object is set up with the `customPubsubTopic` but we're passing it a Decoder with the `DefaultPubsubTopic` + // this subscription object is set up with the `customPubsubTopic1` but we're passing it a Decoder with the `customPubsubTopic2` try { await subscription.subscribe([customDecoder2], messageCollector.callback); } catch (error) { diff --git a/packages/tests/tests/filter/single_node/ping.node.spec.ts b/packages/tests/tests/filter/single_node/ping.node.spec.ts index 5fe775b98e..ab80ddac84 100644 --- a/packages/tests/tests/filter/single_node/ping.node.spec.ts +++ b/packages/tests/tests/filter/single_node/ping.node.spec.ts @@ -1,8 +1,4 @@ -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -17,6 +13,7 @@ import { TestContentTopic, TestDecoder, TestEncoder, + TestShardInfo, validatePingError } from "../utils.js"; @@ -31,9 +28,10 @@ describe("Waku Filter V2: Ping", function () { let messageCollector: MessageCollector; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); + [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); + const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; messageCollector = new MessageCollector(); }); diff --git a/packages/tests/tests/filter/single_node/push.node.spec.ts b/packages/tests/tests/filter/single_node/push.node.spec.ts index 8cab2e1d8c..2919eb535f 100644 --- a/packages/tests/tests/filter/single_node/push.node.spec.ts +++ b/packages/tests/tests/filter/single_node/push.node.spec.ts @@ -1,10 +1,5 @@ import { waitForRemotePeer } from "@waku/core"; -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode, - Protocols -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -23,7 +18,9 @@ import { messageText, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic, + TestShardInfo } from "../utils.js"; describe("Waku Filter V2: FilterPush", function () { @@ -35,12 +32,13 @@ describe("Waku Filter V2: FilterPush", function () { let messageCollector: MessageCollector; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); + [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); + const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; - messageCollector = new MessageCollector(); + messageCollector = new MessageCollector(nwaku); }); afterEachCustom(this, async () => { @@ -68,7 +66,7 @@ describe("Waku Filter V2: FilterPush", function () { await delay(400); await nwaku.restCall( - `/relay/v1/messages/${encodeURIComponent(DefaultPubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(TestPubsubTopic)}`, "POST", { contentTopic: TestContentTopic, @@ -102,7 +100,7 @@ describe("Waku Filter V2: FilterPush", function () { await delay(400); await nwaku.restCall( - `/relay/v1/messages/${encodeURIComponent(DefaultPubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(TestPubsubTopic)}`, "POST", { contentTopic: TestContentTopic, @@ -157,7 +155,7 @@ describe("Waku Filter V2: FilterPush", function () { await delay(400); await nwaku.restCall( - `/relay/v1/messages/${encodeURIComponent(DefaultPubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(TestPubsubTopic)}`, "POST", { payload: Buffer.from(utf8ToBytes(messageText)).toString("base64"), @@ -174,7 +172,7 @@ describe("Waku Filter V2: FilterPush", function () { await delay(400); await nwaku.restCall( - `/relay/v1/messages/${encodeURIComponent(DefaultPubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(TestPubsubTopic)}`, "POST", { contentTopic: TestContentTopic, @@ -196,7 +194,7 @@ describe("Waku Filter V2: FilterPush", function () { await delay(400); await nwaku.restCall( - `/relay/v1/messages/${encodeURIComponent(DefaultPubsubTopic)}`, + `/relay/v1/messages/${encodeURIComponent(TestPubsubTopic)}`, "POST", { contentTopic: TestContentTopic, diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index 523968dc1f..3a7e9bc657 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -1,10 +1,5 @@ import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode, - Protocols -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode, Protocols } from "@waku/interfaces"; import { ecies, generatePrivateKey, @@ -14,14 +9,13 @@ import { } from "@waku/message-encryption"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; +import type { Context } from "mocha"; import { afterEachCustom, beforeEachCustom, delay, generateTestData, - isNwakuAtLeast, - makeLogFileName, MessageCollector, ServiceNode, tearDownNodes, @@ -32,7 +26,9 @@ import { messageText, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic, + TestShardInfo } from "../utils.js"; import { runNodes } from "./utils.js"; @@ -41,23 +37,26 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { // Set the timeout for all tests in this suite. Can be overwritten at test level this.timeout(10000); let waku: LightNode; + let waku2: LightNode; let nwaku: ServiceNode; let nwaku2: ServiceNode; let subscription: ISubscriptionSDK; let messageCollector: MessageCollector; + let ctx: Context; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); + [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); + const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; messageCollector = new MessageCollector(); - await nwaku.ensureSubscriptions(); + await nwaku.ensureSubscriptions([TestPubsubTopic]); }); afterEachCustom(this, async () => { - await tearDownNodes([nwaku, nwaku2], waku); + await tearDownNodes([nwaku, nwaku2], [waku, waku2]); }); it("Subscribe and receive messages via lightPush", async function () { @@ -68,7 +67,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(1)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(1); }); @@ -78,9 +78,14 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { const publicKey = getPublicKey(privateKey); const encoder = ecies.createEncoder({ contentTopic: TestContentTopic, - publicKey + publicKey, + pubsubTopic: TestPubsubTopic }); - const decoder = ecies.createDecoder(TestContentTopic, privateKey); + const decoder = ecies.createDecoder( + TestContentTopic, + privateKey, + TestPubsubTopic + ); await subscription.subscribe([decoder], messageCollector.callback); @@ -90,7 +95,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: TestContentTopic, - expectedVersion: 1 + expectedVersion: 1, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(1); }); @@ -99,9 +105,14 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { const symKey = generateSymmetricKey(); const encoder = symmetric.createEncoder({ contentTopic: TestContentTopic, - symKey + symKey, + pubsubTopic: TestPubsubTopic }); - const decoder = symmetric.createDecoder(TestContentTopic, symKey); + const decoder = symmetric.createDecoder( + TestContentTopic, + symKey, + TestPubsubTopic + ); await subscription.subscribe([decoder], messageCollector.callback); @@ -111,7 +122,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: TestContentTopic, - expectedVersion: 1 + expectedVersion: 1, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(1); }); @@ -132,7 +144,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(1)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(1); }); @@ -145,7 +158,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(1)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); // Send another message on the same topic. @@ -158,7 +172,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(2)).to.eq(true); messageCollector.verifyReceivedMessage(1, { expectedMessageText: newMessageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(2); }); @@ -170,15 +185,19 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(1)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); // Modify subscription to include a new content topic and send a message. const newMessageText = "Filtering still works!"; const newMessagePayload = { payload: utf8ToBytes(newMessageText) }; - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe([newDecoder], messageCollector.callback); await waku.lightPush.send(newEncoder, { payload: utf8ToBytes(newMessageText) @@ -186,7 +205,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(2)).to.eq(true); messageCollector.verifyReceivedMessage(1, { expectedContentTopic: newContentTopic, - expectedMessageText: newMessageText + expectedMessageText: newMessageText, + expectedPubsubTopic: TestPubsubTopic }); // Send another message on the initial content topic to verify it still works. @@ -194,14 +214,15 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(3)).to.eq(true); messageCollector.verifyReceivedMessage(2, { expectedMessageText: newMessageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); expect((await nwaku.messages()).length).to.eq(3); }); it("Subscribe and receives messages on 20 topics", async function () { const topicCount = 20; - const td = generateTestData(topicCount); + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); // Subscribe to all 20 topics. for (let i = 0; i < topicCount; i++) { @@ -220,60 +241,16 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { td.contentTopics.forEach((topic, index) => { messageCollector.verifyReceivedMessage(index, { expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` + expectedMessageText: `Message for Topic ${index + 1}`, + expectedPubsubTopic: TestPubsubTopic }); }); }); it("Subscribe to 100 topics (new limit) at once and receives messages", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - this.timeout(50000); - topicCount = 100; - } else { - // skipping for old versions where the limit is 30 - this.skip(); - } - const td = generateTestData(topicCount); - - await subscription.subscribe(td.decoders, messageCollector.callback); - - // Send a unique message on each topic. - for (let i = 0; i < topicCount; i++) { - await waku.lightPush.send(td.encoders[i], { - payload: utf8ToBytes(`Message for Topic ${i + 1}`) - }); - } - - // Open issue here: https://github.com/waku-org/js-waku/issues/1790 - // That's why we use the try catch block - try { - // Verify that each message was received on the corresponding topic. - expect(await messageCollector.waitForMessages(topicCount)).to.eq(true); - td.contentTopics.forEach((topic, index) => { - messageCollector.verifyReceivedMessage(index, { - expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` - }); - }); - } catch (error) { - console.warn( - "This test still fails because of https://github.com/waku-org/js-waku/issues/1790" - ); - } - }); - - //TODO: remove test when WAKUNODE_IMAGE is 0.25.0 - it("Subscribe to 30 topics (old limit) at once and receives messages", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - // skipping for new versions where the new limit is 100 - this.skip(); - } else { - topicCount = 30; - } - - const td = generateTestData(topicCount); + this.timeout(50000); + const topicCount = 100; + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); await subscription.subscribe(td.decoders, messageCollector.callback); @@ -292,7 +269,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { td.contentTopics.forEach((topic, index) => { messageCollector.verifyReceivedMessage(index, { expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` + expectedMessageText: `Message for Topic ${index + 1}`, + expectedPubsubTopic: TestPubsubTopic }); }); } catch (error) { @@ -303,44 +281,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { }); it("Error when try to subscribe to more than 101 topics (new limit)", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - topicCount = 101; - } else { - // skipping for old versions where the limit is 30 - this.skip(); - } - const td = generateTestData(topicCount); - - try { - await subscription.subscribe(td.decoders, messageCollector.callback); - throw new Error( - `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` - ); - } catch (err) { - if ( - err instanceof Error && - err.message.includes( - `exceeds maximum content topics: ${topicCount - 1}` - ) - ) { - return; - } else { - throw err; - } - } - }); - - //TODO: remove test when WAKUNODE_IMAGE is 0.25.0 - it("Error when try to subscribe to more than 31 topics (old limit)", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - // skipping for new versions where the new limit is 100 - this.skip(); - } else { - topicCount = 31; - } - const td = generateTestData(topicCount); + const topicCount = 101; + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); try { await subscription.subscribe(td.decoders, messageCollector.callback); @@ -364,9 +306,9 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { it("Overlapping topic subscription", async function () { // Define two sets of test data with overlapping topics. const topicCount1 = 2; - const td1 = generateTestData(topicCount1); + const td1 = generateTestData(topicCount1, { pubsubTopic: TestPubsubTopic }); const topicCount2 = 4; - const td2 = generateTestData(topicCount2); + const td2 = generateTestData(topicCount2, { pubsubTopic: TestPubsubTopic }); // Subscribe to the first set of topics. await subscription.subscribe(td1.decoders, messageCollector.callback); @@ -412,19 +354,24 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { ); messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); TEST_STRING.forEach((testItem) => { it(`Subscribe to topic containing ${testItem.description} and receive message`, async function () { const newContentTopic = testItem.value; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe([newDecoder], messageCollector.callback); await waku.lightPush.send(newEncoder, messagePayload); @@ -432,7 +379,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(1)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: newContentTopic + expectedContentTopic: newContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -443,13 +391,16 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { // Create a second subscription on a different topic const { error, subscription: subscription2 } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (error) { throw error; } - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription2.subscribe([newDecoder], messageCollector.callback); await waku.lightPush.send(newEncoder, { payload: utf8ToBytes("M2") }); @@ -458,11 +409,13 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { expect(await messageCollector.waitForMessages(2)).to.eq(true); messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); messageCollector.verifyReceivedMessage(1, { expectedContentTopic: newContentTopic, - expectedMessageText: "M2" + expectedMessageText: "M2", + expectedPubsubTopic: TestPubsubTopic }); }); @@ -470,24 +423,22 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { await subscription.subscribe([TestDecoder], messageCollector.callback); // Set up and start a new nwaku node - nwaku2 = new ServiceNode(makeLogFileName(this) + "2"); - await nwaku2.start({ - filter: true, - lightpush: true, - relay: true - }); + [nwaku2, waku2] = await runNodes(ctx, TestShardInfo); await waku.dial(await nwaku2.getMultiaddrWithId()); await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); const { error, subscription: subscription2 } = - await waku.filter.createSubscription(undefined, await nwaku2.getPeerId()); + await waku.filter.createSubscription(TestShardInfo); if (error) { throw error; } - await nwaku2.ensureSubscriptions([DefaultPubsubTopic]); + await nwaku2.ensureSubscriptions([TestPubsubTopic]); // Send a message using the new subscription - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription2.subscribe([newDecoder], messageCollector.callback); // Making sure that messages are send and reveiced for both subscriptions diff --git a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts index 1607af2107..2fc8c28eb0 100644 --- a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts @@ -1,5 +1,5 @@ import { createDecoder, createEncoder } from "@waku/core"; -import { DefaultPubsubTopic, ISubscriptionSDK } from "@waku/interfaces"; +import { ISubscriptionSDK } from "@waku/interfaces"; import { LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -18,7 +18,9 @@ import { messageText, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic, + TestShardInfo } from "../utils.js"; describe("Waku Filter V2: Unsubscribe", function () { @@ -30,14 +32,13 @@ describe("Waku Filter V2: Unsubscribe", function () { let messageCollector: MessageCollector; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, [DefaultPubsubTopic]); + [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); + const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) subscription = _subscription; messageCollector = new MessageCollector(); - - // Nwaku subscribe to the default pubsub topic - await nwaku.ensureSubscriptions(); + await nwaku.ensureSubscriptions([TestPubsubTopic]); }); afterEachCustom(this, async () => { @@ -57,7 +58,8 @@ describe("Waku Filter V2: Unsubscribe", function () { // Check that from 2 messages send only the 1st was received messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); expect(messageCollector.count).to.eq(1); expect((await nwaku.messages()).length).to.eq(2); @@ -67,8 +69,11 @@ describe("Waku Filter V2: Unsubscribe", function () { // Subscribe to 2 topics and send messages await subscription.subscribe([TestDecoder], messageCollector.callback); const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe([newDecoder], messageCollector.callback); await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M1") }); await waku.lightPush.send(newEncoder, { payload: utf8ToBytes("M2") }); @@ -88,9 +93,12 @@ describe("Waku Filter V2: Unsubscribe", function () { it("Unsubscribe 2 topics - node subscribed to 2 topics", async function () { // Subscribe to 2 topics and send messages await subscription.subscribe([TestDecoder], messageCollector.callback); - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe([newDecoder], messageCollector.callback); await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M1") }); await waku.lightPush.send(newEncoder, { payload: utf8ToBytes("M2") }); @@ -117,7 +125,7 @@ describe("Waku Filter V2: Unsubscribe", function () { // Unsubscribe from topics that the node is not not subscribed to and send again await subscription.unsubscribe([]); - await subscription.unsubscribe(["/test/2/waku-filter"]); + await subscription.unsubscribe(["/test/2/waku-filter/default"]); await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M2") }); expect(await messageCollector.waitForMessages(2)).to.eq(true); @@ -145,7 +153,7 @@ describe("Waku Filter V2: Unsubscribe", function () { it("Unsubscribes all - node subscribed to 10 topics", async function () { // Subscribe to 10 topics and send message const topicCount = 10; - const td = generateTestData(topicCount); + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); await subscription.subscribe(td.decoders, messageCollector.callback); for (let i = 0; i < topicCount; i++) { await waku.lightPush.send(td.encoders[i], { diff --git a/packages/tests/tests/filter/single_node/utils.ts b/packages/tests/tests/filter/single_node/utils.ts index 59195f0302..da2bf7b328 100644 --- a/packages/tests/tests/filter/single_node/utils.ts +++ b/packages/tests/tests/filter/single_node/utils.ts @@ -1,76 +1,22 @@ -import { waitForRemotePeer } from "@waku/core"; -import { - ContentTopicInfo, - DefaultPubsubTopic, - LightNode, - ProtocolCreateOptions, - Protocols, - ShardingParams -} from "@waku/interfaces"; +import { LightNode, Protocols, ShardingParams } from "@waku/interfaces"; import { createLightNode } from "@waku/sdk"; import { Logger } from "@waku/utils"; import { Context } from "mocha"; import { - makeLogFileName, - NOISE_KEY_1, + runNodes as runNodesBuilder, ServiceNode } from "../../../src/index.js"; export const log = new Logger("test:filter:single_node"); -export async function runNodes( +export const runNodes = ( context: Context, - //TODO: change this to use `ShardInfo` instead of `string[]` - pubsubTopics: string[], - shardInfo?: ShardingParams -): Promise<[ServiceNode, LightNode]> { - const nwaku = new ServiceNode(makeLogFileName(context)); - - function isContentTopicInfo(info: ShardingParams): info is ContentTopicInfo { - return (info as ContentTopicInfo).contentTopics !== undefined; - } - - await nwaku.start( - { - filter: true, - lightpush: true, - relay: true, - pubsubTopic: pubsubTopics, - // Conditionally include clusterId if shardInfo exists - ...(shardInfo && { clusterId: shardInfo.clusterId }), - // Conditionally include contentTopic if shardInfo exists and clusterId is 1 - ...(shardInfo && - isContentTopicInfo(shardInfo) && - shardInfo.clusterId === 1 && { contentTopic: shardInfo.contentTopics }) - }, - { retries: 3 } - ); - const waku_options: ProtocolCreateOptions = { - staticNoiseKey: NOISE_KEY_1, - libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } }, - pubsubTopics: shardInfo ? undefined : pubsubTopics, - ...((pubsubTopics.length !== 1 || - pubsubTopics[0] !== DefaultPubsubTopic) && { - shardInfo: shardInfo - }) - }; - - log.info("Starting js waku node with :", JSON.stringify(waku_options)); - let waku: LightNode | undefined; - try { - waku = await createLightNode(waku_options); - await waku.start(); - } catch (error) { - log.error("jswaku node failed to start:", error); - } - - if (waku) { - await waku.dial(await nwaku.getMultiaddrWithId()); - await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); - await nwaku.ensureSubscriptions(pubsubTopics); - return [nwaku, waku]; - } else { - throw new Error("Failed to initialize waku"); - } -} + shardInfo: ShardingParams +): Promise<[ServiceNode, LightNode]> => + runNodesBuilder({ + context, + createNode: createLightNode, + protocols: [Protocols.LightPush, Protocols.Filter], + shardInfo + }); diff --git a/packages/tests/tests/filter/subscribe.node.spec.ts b/packages/tests/tests/filter/subscribe.node.spec.ts index 2cddaa020d..b720408357 100644 --- a/packages/tests/tests/filter/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/subscribe.node.spec.ts @@ -1,9 +1,5 @@ import { createDecoder, createEncoder } from "@waku/core"; -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { ecies, generatePrivateKey, @@ -19,7 +15,6 @@ import { beforeEachCustom, delay, generateTestData, - isNwakuAtLeast, ServiceNodesFleet, TEST_STRING } from "../../src/index.js"; @@ -31,7 +26,9 @@ import { teardownNodesWithRedundancy, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic, + TestShardInfo } from "./utils.js"; const runTests = (strictCheckNodes: boolean): void => { @@ -44,11 +41,11 @@ const runTests = (strictCheckNodes: boolean): void => { beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes( this.ctx, - [DefaultPubsubTopic], + TestShardInfo, strictCheckNodes ); const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (!error) { subscription = _subscription; @@ -85,9 +82,14 @@ const runTests = (strictCheckNodes: boolean): void => { const publicKey = getPublicKey(privateKey); const encoder = ecies.createEncoder({ contentTopic: TestContentTopic, - publicKey + publicKey, + pubsubTopic: TestPubsubTopic }); - const decoder = ecies.createDecoder(TestContentTopic, privateKey); + const decoder = ecies.createDecoder( + TestContentTopic, + privateKey, + TestPubsubTopic + ); await subscription.subscribe( [decoder], @@ -102,7 +104,8 @@ const runTests = (strictCheckNodes: boolean): void => { serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: TestContentTopic, - expectedVersion: 1 + expectedVersion: 1, + expectedPubsubTopic: TestPubsubTopic }); await serviceNodes.confirmMessageLength(1); @@ -112,9 +115,14 @@ const runTests = (strictCheckNodes: boolean): void => { const symKey = generateSymmetricKey(); const encoder = symmetric.createEncoder({ contentTopic: TestContentTopic, - symKey + symKey, + pubsubTopic: TestPubsubTopic }); - const decoder = symmetric.createDecoder(TestContentTopic, symKey); + const decoder = symmetric.createDecoder( + TestContentTopic, + symKey, + TestPubsubTopic + ); await subscription.subscribe( [decoder], @@ -129,7 +137,8 @@ const runTests = (strictCheckNodes: boolean): void => { serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: TestContentTopic, - expectedVersion: 1 + expectedVersion: 1, + expectedPubsubTopic: TestPubsubTopic }); await serviceNodes.confirmMessageLength(1); @@ -148,14 +157,15 @@ const runTests = (strictCheckNodes: boolean): void => { contentTopic: TestContentTopic, payload: utf8ToBytes(messageText) }); - await serviceNodes.sendRelayMessage(relayMessage); + await serviceNodes.sendRelayMessage(relayMessage, TestPubsubTopic); expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( true ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); await serviceNodes.confirmMessageLength(1); @@ -207,15 +217,19 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); // Modify subscription to include a new content topic and send a message. const newMessageText = "Filtering still works!"; const newMessagePayload = { payload: utf8ToBytes(newMessageText) }; - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe( [newDecoder], serviceNodes.messageCollector.callback @@ -228,7 +242,8 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedContentTopic: newContentTopic, - expectedMessageText: newMessageText + expectedMessageText: newMessageText, + expectedPubsubTopic: TestPubsubTopic }); // Send another message on the initial content topic to verify it still works. @@ -238,7 +253,8 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(2, { expectedMessageText: newMessageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); await serviceNodes.confirmMessageLength(3); @@ -246,7 +262,7 @@ const runTests = (strictCheckNodes: boolean): void => { it("Subscribe and receives messages on 20 topics", async function () { const topicCount = 20; - const td = generateTestData(topicCount); + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); // Subscribe to all 20 topics. for (let i = 0; i < topicCount; i++) { @@ -270,65 +286,16 @@ const runTests = (strictCheckNodes: boolean): void => { td.contentTopics.forEach((topic, index) => { serviceNodes.messageCollector.verifyReceivedMessage(index, { expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` + expectedMessageText: `Message for Topic ${index + 1}`, + expectedPubsubTopic: TestPubsubTopic }); }); }); it("Subscribe to 100 topics (new limit) at once and receives messages", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - this.timeout(50000); - topicCount = 100; - } else { - // skipping for old versions where the limit is 30 - this.skip(); - } - const td = generateTestData(topicCount); - - await subscription.subscribe( - td.decoders, - serviceNodes.messageCollector.callback - ); - - // Send a unique message on each topic. - for (let i = 0; i < topicCount; i++) { - await waku.lightPush.send(td.encoders[i], { - payload: utf8ToBytes(`Message for Topic ${i + 1}`) - }); - } - - // Open issue here: https://github.com/waku-org/js-waku/issues/1790 - // That's why we use the try catch block - try { - // Verify that each message was received on the corresponding topic. - expect( - await serviceNodes.messageCollector.waitForMessages(topicCount) - ).to.eq(true); - td.contentTopics.forEach((topic, index) => { - serviceNodes.messageCollector.verifyReceivedMessage(index, { - expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` - }); - }); - } catch (error) { - console.warn( - "This test still fails because of https://github.com/waku-org/js-waku/issues/1790" - ); - } - }); - - //TODO: remove test when WAKUNODE_IMAGE is 0.25.0 - it("Subscribe to 30 topics (old limit) at once and receives messages", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - // skipping for new versions where the new limit is 100 - this.skip(); - } else { - topicCount = 30; - } - - const td = generateTestData(topicCount); + this.timeout(50000); + const topicCount = 100; + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); await subscription.subscribe( td.decoders, @@ -352,7 +319,8 @@ const runTests = (strictCheckNodes: boolean): void => { td.contentTopics.forEach((topic, index) => { serviceNodes.messageCollector.verifyReceivedMessage(index, { expectedContentTopic: topic, - expectedMessageText: `Message for Topic ${index + 1}` + expectedMessageText: `Message for Topic ${index + 1}`, + expectedPubsubTopic: TestPubsubTopic }); }); } catch (error) { @@ -363,47 +331,8 @@ const runTests = (strictCheckNodes: boolean): void => { }); it("Error when try to subscribe to more than 101 topics (new limit)", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - topicCount = 101; - } else { - // skipping for old versions where the limit is 30 - this.skip(); - } - const td = generateTestData(topicCount); - - try { - await subscription.subscribe( - td.decoders, - serviceNodes.messageCollector.callback - ); - throw new Error( - `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` - ); - } catch (err) { - if ( - err instanceof Error && - err.message.includes( - `exceeds maximum content topics: ${topicCount - 1}` - ) - ) { - return; - } else { - throw err; - } - } - }); - - //TODO: remove test when WAKUNODE_IMAGE is 0.25.0 - it("Error when try to subscribe to more than 31 topics (old limit)", async function () { - let topicCount: number; - if (isNwakuAtLeast("0.25.0")) { - // skipping for new versions where the new limit is 100 - this.skip(); - } else { - topicCount = 31; - } - const td = generateTestData(topicCount); + const topicCount = 101; + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); try { await subscription.subscribe( @@ -430,9 +359,13 @@ const runTests = (strictCheckNodes: boolean): void => { it("Overlapping topic subscription", async function () { // Define two sets of test data with overlapping topics. const topicCount1 = 2; - const td1 = generateTestData(topicCount1); + const td1 = generateTestData(topicCount1, { + pubsubTopic: TestPubsubTopic + }); const topicCount2 = 4; - const td2 = generateTestData(topicCount2); + const td2 = generateTestData(topicCount2, { + pubsubTopic: TestPubsubTopic + }); // Subscribe to the first set of topics. await subscription.subscribe( @@ -489,19 +422,24 @@ const runTests = (strictCheckNodes: boolean): void => { ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); TEST_STRING.forEach((testItem) => { it(`Subscribe to topic containing ${testItem.description} and receive message`, async function () { const newContentTopic = testItem.value; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe( [newDecoder], @@ -514,7 +452,8 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: newContentTopic + expectedContentTopic: newContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -528,13 +467,16 @@ const runTests = (strictCheckNodes: boolean): void => { // Create a second subscription on a different topic const { error, subscription: subscription2 } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription(TestShardInfo); if (error) { throw error; } - const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newContentTopic = "/test/2/waku-filter/default"; + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription2.subscribe( [newDecoder], serviceNodes.messageCollector.callback @@ -548,11 +490,13 @@ const runTests = (strictCheckNodes: boolean): void => { ); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedContentTopic: newContentTopic, - expectedMessageText: "M2" + expectedMessageText: "M2", + expectedPubsubTopic: TestPubsubTopic }); }); }); diff --git a/packages/tests/tests/filter/unsubscribe.node.spec.ts b/packages/tests/tests/filter/unsubscribe.node.spec.ts index 7b7d0ad3f9..9dc362bb08 100644 --- a/packages/tests/tests/filter/unsubscribe.node.spec.ts +++ b/packages/tests/tests/filter/unsubscribe.node.spec.ts @@ -1,9 +1,5 @@ import { createDecoder, createEncoder } from "@waku/core"; -import { - DefaultPubsubTopic, - ISubscriptionSDK, - LightNode -} from "@waku/interfaces"; +import { ISubscriptionSDK, LightNode } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -15,13 +11,15 @@ import { } from "../../src/index.js"; import { + ClusterId, messagePayload, messageText, runMultipleNodes, teardownNodesWithRedundancy, TestContentTopic, TestDecoder, - TestEncoder + TestEncoder, + TestPubsubTopic } from "./utils.js"; const runTests = (strictCheckNodes: boolean): void => { @@ -33,11 +31,15 @@ const runTests = (strictCheckNodes: boolean): void => { let subscription: ISubscriptionSDK; beforeEachCustom(this, async () => { - [serviceNodes, waku] = await runMultipleNodes(this.ctx, [ - DefaultPubsubTopic - ]); + [serviceNodes, waku] = await runMultipleNodes(this.ctx, { + contentTopics: [TestContentTopic], + clusterId: ClusterId + }); const { error, subscription: _subscription } = - await waku.filter.createSubscription(); + await waku.filter.createSubscription({ + contentTopics: [TestContentTopic], + clusterId: ClusterId + }); if (!error) { subscription = _subscription; @@ -82,8 +84,11 @@ const runTests = (strictCheckNodes: boolean): void => { serviceNodes.messageCollector.callback ); const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe( [newDecoder], serviceNodes.messageCollector.callback @@ -114,8 +119,11 @@ const runTests = (strictCheckNodes: boolean): void => { serviceNodes.messageCollector.callback ); const newContentTopic = "/test/2/waku-filter"; - const newEncoder = createEncoder({ contentTopic: newContentTopic }); - const newDecoder = createDecoder(newContentTopic); + const newEncoder = createEncoder({ + contentTopic: newContentTopic, + pubsubTopic: TestPubsubTopic + }); + const newDecoder = createDecoder(newContentTopic, TestPubsubTopic); await subscription.subscribe( [newDecoder], serviceNodes.messageCollector.callback @@ -191,7 +199,7 @@ const runTests = (strictCheckNodes: boolean): void => { it("Unsubscribes all - node subscribed to 10 topics", async function () { // Subscribe to 10 topics and send message const topicCount = 10; - const td = generateTestData(topicCount); + const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); await subscription.subscribe( td.decoders, serviceNodes.messageCollector.callback diff --git a/packages/tests/tests/filter/utils.ts b/packages/tests/tests/filter/utils.ts index 1f269c94c1..5517ed5e7f 100644 --- a/packages/tests/tests/filter/utils.ts +++ b/packages/tests/tests/filter/utils.ts @@ -1,6 +1,5 @@ import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; import { - DefaultPubsubTopic, ISubscriptionSDK, LightNode, ProtocolCreateOptions, @@ -10,7 +9,7 @@ import { } from "@waku/interfaces"; import { createLightNode } from "@waku/sdk"; import { - ensureShardingConfigured, + contentTopicToPubsubTopic, Logger, shardInfoToPubsubTopics } from "@waku/utils"; @@ -26,9 +25,21 @@ import { // Constants for test configuration. export const log = new Logger("test:filter"); -export const TestContentTopic = "/test/1/waku-filter"; -export const TestEncoder = createEncoder({ contentTopic: TestContentTopic }); -export const TestDecoder = createDecoder(TestContentTopic); +export const TestContentTopic = "/test/1/waku-filter/default"; +export const ClusterId = 2; +export const TestShardInfo = { + contentTopics: [TestContentTopic], + clusterId: ClusterId +}; +export const TestPubsubTopic = contentTopicToPubsubTopic( + TestContentTopic, + ClusterId +); +export const TestEncoder = createEncoder({ + contentTopic: TestContentTopic, + pubsubTopic: TestPubsubTopic +}); +export const TestDecoder = createDecoder(TestContentTopic, TestPubsubTopic); export const messageText = "Filtering works!"; export const messagePayload = { payload: utf8ToBytes(messageText) }; @@ -55,20 +66,19 @@ export async function validatePingError( export async function runMultipleNodes( context: Context, - //TODO: change this to use `ShardInfo` instead of `string[]` - pubsubTopics: string[], + shardInfo: ShardingParams, strictChecking: boolean = false, - shardInfo?: ShardingParams, numServiceNodes = 3, withoutFilter = false ): Promise<[ServiceNodesFleet, LightNode]> { + const pubsubTopics = shardInfoToPubsubTopics(shardInfo); // create numServiceNodes nodes const serviceNodes = await ServiceNodesFleet.createAndRun( context, pubsubTopics, numServiceNodes, strictChecking, - shardInfo ? ensureShardingConfigured(shardInfo).shardInfo : shardInfo, + shardInfo, undefined, withoutFilter ); @@ -78,11 +88,8 @@ export async function runMultipleNodes( libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } }, - pubsubTopics: shardInfo ? shardInfoToPubsubTopics(shardInfo) : pubsubTopics, - ...((pubsubTopics.length !== 1 || - pubsubTopics[0] !== DefaultPubsubTopic) && { - shardInfo: shardInfo - }) + pubsubTopics, + shardInfo }; log.info("Starting js waku node with :", JSON.stringify(waku_options)); diff --git a/packages/tests/tests/getPeers.spec.ts b/packages/tests/tests/getPeers.spec.ts index bc5f6e690b..242eb09815 100644 --- a/packages/tests/tests/getPeers.spec.ts +++ b/packages/tests/tests/getPeers.spec.ts @@ -20,9 +20,8 @@ import Sinon from "sinon"; import { afterEachCustom, beforeEachCustom, - isNwakuAtLeast, + delay, makeLogFileName, - resolveAutoshardingCluster, ServiceNode, tearDownNodes } from "../src/index.js"; @@ -32,13 +31,7 @@ describe("getConnectedPeersForProtocolAndShard", function () { let serviceNode1: ServiceNode; let serviceNode2: ServiceNode; const contentTopic = "/test/2/waku-light-push/utf8"; - const autoshardingClusterId = resolveAutoshardingCluster(6); - - before(async () => { - if (!isNwakuAtLeast("0.27.0")) { - this.ctx.skip(); - } - }); + const autoshardingClusterId = 6; beforeEachCustom(this, async () => { serviceNode1 = new ServiceNode(makeLogFileName(this.ctx) + "1"); @@ -170,6 +163,7 @@ describe("getConnectedPeersForProtocolAndShard", function () { waku = await createLightNode({ shardInfo: shardInfo2 }); await waku.libp2p.dialProtocol(serviceNode1Ma, LightPushCodec); + await delay(500); await waku.libp2p.dialProtocol(serviceNode2Ma, LightPushCodec); await waku.start(); @@ -223,6 +217,7 @@ describe("getConnectedPeersForProtocolAndShard", function () { waku = await createLightNode({ shardInfo: shardInfo2 }); await waku.libp2p.dialProtocol(serviceNodeMa1, LightPushCodec); + await delay(500); await waku.libp2p.dialProtocol(serviceNodeMa2, LightPushCodec); await waku.start(); await waitForRemotePeer(waku, [Protocols.LightPush]); @@ -362,6 +357,7 @@ describe("getConnectedPeersForProtocolAndShard", function () { waku = await createLightNode({ shardInfo: shardInfo2 }); await waku.libp2p.dialProtocol(serviceNode1Ma, LightPushCodec); + await delay(500); await waku.libp2p.dialProtocol(serviceNode2Ma, LightPushCodec); await waku.start(); @@ -416,6 +412,7 @@ describe("getConnectedPeersForProtocolAndShard", function () { waku = await createLightNode({ shardInfo: shardInfo2 }); await waku.libp2p.dialProtocol(serviceNodeMa1, LightPushCodec); + await delay(500); await waku.libp2p.dialProtocol(serviceNodeMa2, LightPushCodec); await waku.start(); await waitForRemotePeer(waku, [Protocols.LightPush]); diff --git a/packages/tests/tests/light-push/index.node.spec.ts b/packages/tests/tests/light-push/index.node.spec.ts index 896a9b27fe..ae12db79a4 100644 --- a/packages/tests/tests/light-push/index.node.spec.ts +++ b/packages/tests/tests/light-push/index.node.spec.ts @@ -1,10 +1,5 @@ import { createEncoder } from "@waku/core"; -import { - DefaultPubsubTopic, - IRateLimitProof, - LightNode, - ProtocolError -} from "@waku/interfaces"; +import { IRateLimitProof, LightNode, ProtocolError } from "@waku/interfaces"; import { utf8ToBytes } from "@waku/sdk"; import { expect } from "chai"; @@ -24,8 +19,10 @@ import { messagePayload, messageText, TestContentTopic, - TestEncoder -} from "./utils"; + TestEncoder, + TestPubsubTopic, + TestShardInfo +} from "./utils.js"; const runTests = (strictNodeCheck: boolean): void => { const numServiceNodes = 3; @@ -38,9 +35,8 @@ const runTests = (strictNodeCheck: boolean): void => { beforeEachCustom(this, async () => { [serviceNodes, waku] = await runMultipleNodes( this.ctx, - [DefaultPubsubTopic], + TestShardInfo, strictNodeCheck, - undefined, numServiceNodes, true ); @@ -57,12 +53,15 @@ const runTests = (strictNodeCheck: boolean): void => { }); expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: testItem.value, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -77,14 +76,17 @@ const runTests = (strictNodeCheck: boolean): void => { expect(pushResponse.successes.length).to.eq(numServiceNodes); } - expect(await serviceNodes.messageCollector.waitForMessages(30)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(30, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); for (let i = 0; i < 30; i++) { serviceNodes.messageCollector.verifyReceivedMessage(i, { expectedMessageText: generateMessageText(i), - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); } }); @@ -95,21 +97,23 @@ const runTests = (strictNodeCheck: boolean): void => { }); expect(pushResponse.successes.length).to.eq(0); - console.log("validated 1"); + expect(pushResponse.failures?.map((failure) => failure.error)).to.include( ProtocolError.EMPTY_PAYLOAD ); - console.log("validated 2"); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - false - ); - console.log("validated 3"); + + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(false); }); TEST_STRING.forEach((testItem) => { it(`Push message with content topic containing ${testItem.description}`, async function () { const customEncoder = createEncoder({ - contentTopic: testItem.value + contentTopic: testItem.value, + pubsubTopic: TestPubsubTopic }); const pushResponse = await waku.lightPush.send( customEncoder, @@ -117,12 +121,15 @@ const runTests = (strictNodeCheck: boolean): void => { ); expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: testItem.value + expectedContentTopic: testItem.value, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -141,7 +148,8 @@ const runTests = (strictNodeCheck: boolean): void => { it("Push message with meta", async function () { const customTestEncoder = createEncoder({ contentTopic: TestContentTopic, - metaSetter: () => new Uint8Array(10) + metaSetter: () => new Uint8Array(10), + pubsubTopic: TestPubsubTopic }); const pushResponse = await waku.lightPush.send( @@ -150,18 +158,22 @@ const runTests = (strictNodeCheck: boolean): void => { ); expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); it("Fails to push message with large meta", async function () { const customTestEncoder = createEncoder({ contentTopic: TestContentTopic, + pubsubTopic: TestPubsubTopic, metaSetter: () => new Uint8Array(105024) // see the note below *** }); @@ -179,21 +191,26 @@ const runTests = (strictNodeCheck: boolean): void => { if (serviceNodes.type == "go-waku") { expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); } else { expect(pushResponse.successes.length).to.eq(0); expect( pushResponse.failures?.map((failure) => failure.error) ).to.include(ProtocolError.REMOTE_PEER_REJECTED); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - false - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(false); } }); @@ -214,12 +231,15 @@ const runTests = (strictNodeCheck: boolean): void => { }); expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); @@ -235,13 +255,16 @@ const runTests = (strictNodeCheck: boolean): void => { }); expect(pushResponse.successes.length).to.eq(numServiceNodes); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - true - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(true); serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedTimestamp: testItem, - expectedContentTopic: TestContentTopic + expectedContentTopic: TestContentTopic, + expectedPubsubTopic: TestPubsubTopic }); }); }); @@ -264,9 +287,11 @@ const runTests = (strictNodeCheck: boolean): void => { expect(pushResponse.failures?.map((failure) => failure.error)).to.include( ProtocolError.SIZE_TOO_BIG ); - expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq( - false - ); + expect( + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: TestPubsubTopic + }) + ).to.eq(false); }); }); }; diff --git a/packages/tests/tests/metadata.spec.ts b/packages/tests/tests/metadata.spec.ts index 1e91843def..b501d86610 100644 --- a/packages/tests/tests/metadata.spec.ts +++ b/packages/tests/tests/metadata.spec.ts @@ -75,12 +75,12 @@ describe("Metadata Protocol", function () { it("same cluster, different shard: nodes connect", async function () { const shardInfo1: ShardInfo = { - clusterId: 0, + clusterId: 2, shards: [1] }; const shardInfo2: ShardInfo = { - clusterId: 0, + clusterId: 2, shards: [2] }; diff --git a/packages/tests/tests/utils.spec.ts b/packages/tests/tests/utils.spec.ts index eb2e6d4a3e..ee2765b199 100644 --- a/packages/tests/tests/utils.spec.ts +++ b/packages/tests/tests/utils.spec.ts @@ -1,10 +1,5 @@ -import { createDecoder, createEncoder, waitForRemotePeer } from "@waku/core"; -import { - DefaultPubsubTopic, - type LightNode, - Protocols -} from "@waku/interfaces"; -import { createLightNode } from "@waku/sdk"; +import { createDecoder, createEncoder } from "@waku/core"; +import { type LightNode } from "@waku/interfaces"; import { toAsyncIterator } from "@waku/utils"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import chai, { expect } from "chai"; @@ -14,36 +9,32 @@ import { afterEachCustom, beforeEachCustom, delay, - makeLogFileName, - NOISE_KEY_1, ServiceNode, tearDownNodes } from "../src/index.js"; +import { runNodes } from "./filter/single_node/utils.js"; + chai.use(chaiAsPromised); -const TestContentTopic = "/test/1/waku-filter"; -const TestEncoder = createEncoder({ contentTopic: TestContentTopic }); -const TestDecoder = createDecoder(TestContentTopic); +const TestContentTopic = "/test/1/waku-filter/default"; +const TestShardInfo = { + contentTopics: [TestContentTopic], + clusterId: 3 +}; + +const TestEncoder = createEncoder({ + contentTopic: TestContentTopic, + pubsubTopicShardInfo: TestShardInfo +}); +const TestDecoder = createDecoder(TestContentTopic, TestShardInfo); describe("Util: toAsyncIterator: Filter", function () { let waku: LightNode; let nwaku: ServiceNode; beforeEachCustom(this, async () => { - nwaku = new ServiceNode(makeLogFileName(this.ctx)); - await nwaku.start({ - filter: true, - lightpush: true, - relay: true - }); - waku = await createLightNode({ - staticNoiseKey: NOISE_KEY_1, - libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } } - }); - await waku.start(); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); + [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); }); afterEachCustom(this, async () => { @@ -63,7 +54,7 @@ describe("Util: toAsyncIterator: Filter", function () { const { value } = await iterator.next(); expect(value.contentTopic).to.eq(TestContentTopic); - expect(value.pubsubTopic).to.eq(DefaultPubsubTopic); + expect(value.pubsubTopic).to.eq(TestDecoder.pubsubTopic); expect(bytesToUtf8(value.payload)).to.eq(messageText); }); 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 c345ea1d40..2e50b036d3 100644 --- a/packages/tests/tests/wait_for_remote_peer.node.spec.ts +++ b/packages/tests/tests/wait_for_remote_peer.node.spec.ts @@ -1,6 +1,6 @@ import { waitForRemotePeer } from "@waku/core"; import type { LightNode, RelayNode } from "@waku/interfaces"; -import { DefaultPubsubTopic, Protocols } from "@waku/interfaces"; +import { Protocols } from "@waku/interfaces"; import { createLightNode } from "@waku/sdk"; import { createRelayNode } from "@waku/sdk/relay"; import { expect } from "chai"; @@ -14,6 +14,12 @@ import { tearDownNodes } from "../src/index.js"; +import { + runRelayNodes, + TestPubsubTopic, + TestShardInfo +} from "./relay/utils.js"; + describe("Wait for remote peer", function () { let waku1: RelayNode; let waku2: LightNode; @@ -25,23 +31,10 @@ describe("Wait for remote peer", function () { it("Relay - dialed first", async function () { this.timeout(20_000); - nwaku = new ServiceNode(makeLogFileName(this)); - await nwaku.start({ - relay: true, - store: false, - filter: false, - lightpush: false - }); + [nwaku, waku1] = await runRelayNodes(this, TestShardInfo); const multiAddrWithId = await nwaku.getMultiaddrWithId(); - waku1 = await createRelayNode({ - staticNoiseKey: NOISE_KEY_1 - }); - await waku1.start(); - await waku1.dial(multiAddrWithId); - await delay(1000); - await waitForRemotePeer(waku1, [Protocols.Relay]); - const peers = waku1.relay.getMeshPeers(DefaultPubsubTopic); + const peers = waku1.relay.getMeshPeers(TestPubsubTopic); const nimPeerId = multiAddrWithId.getPeerId(); expect(nimPeerId).to.not.be.undefined; @@ -252,23 +245,10 @@ describe("Wait for remote peer", function () { it("Privacy Node - default protocol", async function () { this.timeout(20_000); - nwaku = new ServiceNode(makeLogFileName(this)); - await nwaku.start({ - filter: false, - lightpush: false, - relay: true, - store: false - }); + [nwaku, waku1] = await runRelayNodes(this, TestShardInfo); const multiAddrWithId = await nwaku.getMultiaddrWithId(); - waku1 = await createRelayNode({ - staticNoiseKey: NOISE_KEY_1 - }); - await waku1.start(); - await waku1.dial(multiAddrWithId); - await waitForRemotePeer(waku1); - - const peers = waku1.relay.getMeshPeers(DefaultPubsubTopic); + const peers = waku1.relay.getMeshPeers(TestPubsubTopic); const nimPeerId = multiAddrWithId.getPeerId(); From 85cb39344924fa6a3fe79c74c3ea91810ce0455b Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 29 Apr 2024 19:57:15 +0530 Subject: [PATCH 10/18] chore: resolve conflicts & merge (3/n) --- .github/workflows/ci.yml | 4 +- packages/message-encryption/src/ecies.spec.ts | 22 ++---- packages/message-encryption/src/ecies.ts | 3 +- .../message-encryption/src/symmetric.spec.ts | 16 ++-- packages/message-hash/src/index.spec.ts | 40 ++++++---- packages/message-hash/src/index.ts | 27 ++++--- packages/relay/src/message_validator.spec.ts | 74 +++++++++---------- packages/tests/src/run-tests.js | 2 +- 8 files changed, 96 insertions(+), 92 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70833f0a8f..90c802b490 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,14 +72,14 @@ jobs: uses: ./.github/workflows/test-node.yml secrets: inherit with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.26.0' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.27.0' }} test_type: node allure_reports: true node_optional: uses: ./.github/workflows/test-node.yml with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.26.0' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.27.0' }} test_type: node-optional node_with_nwaku_master: diff --git a/packages/message-encryption/src/ecies.spec.ts b/packages/message-encryption/src/ecies.spec.ts index eeb05b7ecd..55743820a0 100644 --- a/packages/message-encryption/src/ecies.spec.ts +++ b/packages/message-encryption/src/ecies.spec.ts @@ -1,20 +1,22 @@ import { IProtoMessage } from "@waku/interfaces"; +import { contentTopicToPubsubTopic } from "@waku/utils"; import { expect } from "chai"; import fc from "fast-check"; import { getPublicKey } from "./crypto/index.js"; import { createDecoder, createEncoder } from "./ecies.js"; +const contentTopic = "/js-waku/1/tests/bytes"; +const pubsubTopic = contentTopicToPubsubTopic(contentTopic); + describe("Ecies Encryption", function () { this.timeout(20000); it("Round trip binary encryption [ecies, no signature]", async function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async (pubsubTopic, contentTopic, payload, privateKey) => { + async (payload, privateKey) => { const publicKey = getPublicKey(privateKey); const encoder = createEncoder({ @@ -46,18 +48,10 @@ describe("Ecies Encryption", function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async ( - pubsubTopic, - contentTopic, - payload, - alicePrivateKey, - bobPrivateKey - ) => { + async (payload, alicePrivateKey, bobPrivateKey) => { const alicePublicKey = getPublicKey(alicePrivateKey); const bobPublicKey = getPublicKey(bobPrivateKey); @@ -89,11 +83,9 @@ describe("Ecies Encryption", function () { it("Check meta is set [ecies]", async function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async (pubsubTopic, contentTopic, payload, privateKey) => { + async (payload, privateKey) => { const publicKey = getPublicKey(privateKey); const metaSetter = ( msg: IProtoMessage & { meta: undefined } diff --git a/packages/message-encryption/src/ecies.ts b/packages/message-encryption/src/ecies.ts index 31c9069656..b084c6a9bc 100644 --- a/packages/message-encryption/src/ecies.ts +++ b/packages/message-encryption/src/ecies.ts @@ -1,7 +1,6 @@ import { Decoder as DecoderV0 } from "@waku/core/lib/message/version_0"; import { type EncoderOptions as BaseEncoderOptions, - DefaultPubsubTopic, type IDecoder, type IEncoder, type IMessage, @@ -200,7 +199,7 @@ class Decoder extends DecoderV0 implements IDecoder { export function createDecoder( contentTopic: string, privateKey: Uint8Array, - pubsubTopicShardInfo: SingleShardInfo | PubsubTopic = DefaultPubsubTopic + pubsubTopicShardInfo?: SingleShardInfo | PubsubTopic ): Decoder { return new Decoder( determinePubsubTopic(contentTopic, pubsubTopicShardInfo), diff --git a/packages/message-encryption/src/symmetric.spec.ts b/packages/message-encryption/src/symmetric.spec.ts index cd604eb7d0..9016f66604 100644 --- a/packages/message-encryption/src/symmetric.spec.ts +++ b/packages/message-encryption/src/symmetric.spec.ts @@ -1,19 +1,21 @@ import { IProtoMessage } from "@waku/interfaces"; +import { contentTopicToPubsubTopic } from "@waku/utils"; import { expect } from "chai"; import fc from "fast-check"; import { getPublicKey } from "./crypto/index.js"; import { createDecoder, createEncoder } from "./symmetric.js"; +const contentTopic = "/js-waku/1/tests/bytes"; +const pubsubTopic = contentTopicToPubsubTopic(contentTopic); + describe("Symmetric Encryption", function () { it("Round trip binary encryption [symmetric, no signature]", async function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async (pubsubTopic, contentTopic, payload, symKey) => { + async (payload, symKey) => { const encoder = createEncoder({ contentTopic, symKey @@ -41,12 +43,10 @@ describe("Symmetric Encryption", function () { it("Round trip binary encryption [symmetric, signature]", async function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async (pubsubTopic, contentTopic, payload, sigPrivKey, symKey) => { + async (payload, sigPrivKey, symKey) => { const sigPubKey = getPublicKey(sigPrivKey); const encoder = createEncoder({ @@ -77,11 +77,9 @@ describe("Symmetric Encryption", function () { it("Check meta is set [symmetric]", async function () { await fc.assert( fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), fc.uint8Array({ minLength: 1 }), fc.uint8Array({ min: 1, minLength: 32, maxLength: 32 }), - async (pubsubTopic, contentTopic, payload, symKey) => { + async (payload, symKey) => { const metaSetter = ( msg: IProtoMessage & { meta: undefined } ): Uint8Array => { diff --git a/packages/message-hash/src/index.spec.ts b/packages/message-hash/src/index.spec.ts index 11b32dad78..e650dfbdff 100644 --- a/packages/message-hash/src/index.spec.ts +++ b/packages/message-hash/src/index.spec.ts @@ -6,63 +6,73 @@ import { messageHash } from "./index.js"; // https://rfc.vac.dev/spec/14/#test-vectors describe("RFC Test Vectors", () => { - it("Waku message hash computation", () => { + it("Waku message hash computation (meta size of 12 bytes)", () => { const expectedHash = - "4fdde1099c9f77f6dae8147b6b3179aba1fc8e14a7bf35203fc253ee479f135f"; - + "64cce733fed134e83da02b02c6f689814872b1a0ac97ea56b76095c3c72bfe05"; const pubsubTopic = "/waku/2/default-waku/proto"; const message: IProtoMessage = { payload: hexToBytes("0x010203045445535405060708"), contentTopic: "/waku/2/default-content/proto", meta: hexToBytes("0x73757065722d736563726574"), + timestamp: BigInt("0x175789bfa23f8400"), ephemeral: undefined, rateLimitProof: undefined, - timestamp: undefined, version: undefined }; - const hash = messageHash(pubsubTopic, message); + expect(bytesToHex(hash)).to.equal(expectedHash); + }); + it("Waku message hash computation (meta size of 64 bytes)", () => { + const expectedHash = + "7158b6498753313368b9af8f6e0a0a05104f68f972981da42a43bc53fb0c1b27"; + const pubsubTopic = "/waku/2/default-waku/proto"; + const message: IProtoMessage = { + payload: hexToBytes("0x010203045445535405060708"), + contentTopic: "/waku/2/default-content/proto", + meta: hexToBytes( + "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + ), + timestamp: BigInt("0x175789bfa23f8400"), + ephemeral: undefined, + rateLimitProof: undefined, + version: undefined + }; + const hash = messageHash(pubsubTopic, message); expect(bytesToHex(hash)).to.equal(expectedHash); }); it("Waku message hash computation (meta attribute not present)", () => { const expectedHash = - "87619d05e563521d9126749b45bd4cc2430df0607e77e23572d874ed9c1aaa62"; - + "a2554498b31f5bcdfcbf7fa58ad1c2d45f0254f3f8110a85588ec3cf10720fd8"; const pubsubTopic = "/waku/2/default-waku/proto"; const message: IProtoMessage = { payload: hexToBytes("0x010203045445535405060708"), contentTopic: "/waku/2/default-content/proto", meta: undefined, + timestamp: BigInt("0x175789bfa23f8400"), ephemeral: undefined, rateLimitProof: undefined, - timestamp: undefined, version: undefined }; - const hash = messageHash(pubsubTopic, message); - expect(bytesToHex(hash)).to.equal(expectedHash); }); it("Waku message hash computation (payload length 0)", () => { const expectedHash = - "e1a9596237dbe2cc8aaf4b838c46a7052df6bc0d42ba214b998a8bfdbe8487d6"; - + "483ea950cb63f9b9d6926b262bb36194d3f40a0463ce8446228350bd44e96de4"; const pubsubTopic = "/waku/2/default-waku/proto"; const message: IProtoMessage = { payload: new Uint8Array(), contentTopic: "/waku/2/default-content/proto", meta: hexToBytes("0x73757065722d736563726574"), + timestamp: BigInt("0x175789bfa23f8400"), ephemeral: undefined, rateLimitProof: undefined, - timestamp: undefined, version: undefined }; - const hash = messageHash(pubsubTopic, message); - expect(bytesToHex(hash)).to.equal(expectedHash); }); }); diff --git a/packages/message-hash/src/index.ts b/packages/message-hash/src/index.ts index 4bf9842e19..37f9c80c60 100644 --- a/packages/message-hash/src/index.ts +++ b/packages/message-hash/src/index.ts @@ -1,6 +1,12 @@ import { sha256 } from "@noble/hashes/sha256"; import type { IProtoMessage } from "@waku/interfaces"; -import { bytesToUtf8, concat, utf8ToBytes } from "@waku/utils/bytes"; +import { isDefined } from "@waku/utils"; +import { + bytesToUtf8, + concat, + numberToBytes, + utf8ToBytes +} from "@waku/utils/bytes"; /** * Deterministic Message Hashing as defined in @@ -12,19 +18,20 @@ export function messageHash( ): Uint8Array { const pubsubTopicBytes = utf8ToBytes(pubsubTopic); const contentTopicBytes = utf8ToBytes(message.contentTopic); + const timestampBytes = message.timestamp + ? numberToBytes(message.timestamp) + : undefined; - let bytes; - - if (message.meta) { - bytes = concat([ + const bytes = concat( + [ pubsubTopicBytes, message.payload, contentTopicBytes, - message.meta - ]); - } else { - bytes = concat([pubsubTopicBytes, message.payload, contentTopicBytes]); - } + message.meta, + timestampBytes + ].filter(isDefined) + ); + return sha256(bytes); } diff --git a/packages/relay/src/message_validator.spec.ts b/packages/relay/src/message_validator.spec.ts index a26f4ad27b..c5fb36a444 100644 --- a/packages/relay/src/message_validator.spec.ts +++ b/packages/relay/src/message_validator.spec.ts @@ -2,57 +2,55 @@ import { TopicValidatorResult } from "@libp2p/interface"; import type { UnsignedMessage } from "@libp2p/interface"; import { createSecp256k1PeerId } from "@libp2p/peer-id-factory"; import { createEncoder } from "@waku/core"; +import { determinePubsubTopic } from "@waku/utils"; import { expect } from "chai"; import fc from "fast-check"; import { messageValidator } from "./message_validator.js"; +const TestContentTopic = "/app/1/topic/utf8"; +const TestPubsubTopic = determinePubsubTopic(TestContentTopic); + describe("Message Validator", () => { it("Accepts a valid Waku Message", async () => { await fc.assert( - fc.asyncProperty( - fc.uint8Array({ minLength: 1 }), - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), - async (payload, pubsubTopic, contentTopic) => { - const peerId = await createSecp256k1PeerId(); - - const encoder = createEncoder({ contentTopic }); - const bytes = await encoder.toWire({ payload }); - - const message: UnsignedMessage = { - type: "unsigned", - topic: pubsubTopic, - data: bytes - }; - - const result = messageValidator(peerId, message); - - expect(result).to.eq(TopicValidatorResult.Accept); - } - ) + fc.asyncProperty(fc.uint8Array({ minLength: 1 }), async (payload) => { + const peerId = await createSecp256k1PeerId(); + + const encoder = createEncoder({ + contentTopic: TestContentTopic, + pubsubTopic: TestPubsubTopic + }); + const bytes = await encoder.toWire({ payload }); + + const message: UnsignedMessage = { + type: "unsigned", + topic: TestPubsubTopic, + data: bytes + }; + + const result = messageValidator(peerId, message); + + expect(result).to.eq(TopicValidatorResult.Accept); + }) ); }); it("Rejects garbage", async () => { await fc.assert( - fc.asyncProperty( - fc.uint8Array(), - fc.string(), - async (data, pubsubTopic) => { - const peerId = await createSecp256k1PeerId(); - - const message: UnsignedMessage = { - type: "unsigned", - topic: pubsubTopic, - data - }; - - const result = messageValidator(peerId, message); - - expect(result).to.eq(TopicValidatorResult.Reject); - } - ) + fc.asyncProperty(fc.uint8Array(), async (data) => { + const peerId = await createSecp256k1PeerId(); + + const message: UnsignedMessage = { + type: "unsigned", + topic: TestPubsubTopic, + data + }; + + const result = messageValidator(peerId, message); + + expect(result).to.eq(TopicValidatorResult.Reject); + }) ); }); }); diff --git a/packages/tests/src/run-tests.js b/packages/tests/src/run-tests.js index b2cbdc2bd2..bed0e50bae 100644 --- a/packages/tests/src/run-tests.js +++ b/packages/tests/src/run-tests.js @@ -3,7 +3,7 @@ import { promisify } from "util"; const execAsync = promisify(exec); -const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.26.0"; +const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.27.0"; async function main() { try { From ffb9b2d26c8cdf29681d51f77295cd4012830799 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 29 Apr 2024 19:59:50 +0530 Subject: [PATCH 11/18] chore: resolve conflicts & merge (4/n) --- packages/proto/src/generated/store.ts | 4 ++-- packages/proto/src/lib/store.proto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto/src/generated/store.ts b/packages/proto/src/generated/store.ts index 6a296fa444..82eef846d8 100644 --- a/packages/proto/src/generated/store.ts +++ b/packages/proto/src/generated/store.ts @@ -377,14 +377,14 @@ export namespace HistoryResponse { export enum HistoryError { NONE = 'NONE', INVALID_CURSOR = 'INVALID_CURSOR', - TOO_MANY_RESULTS = 'TOO_MANY_RESULTS', + TOO_MANY_REQUESTS = 'TOO_MANY_REQUESTS', SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE' } enum __HistoryErrorValues { NONE = 0, INVALID_CURSOR = 1, - TOO_MANY_RESULTS = 429, + TOO_MANY_REQUESTS = 429, SERVICE_UNAVAILABLE = 503 } diff --git a/packages/proto/src/lib/store.proto b/packages/proto/src/lib/store.proto index 48c0c95fa7..a083f88524 100644 --- a/packages/proto/src/lib/store.proto +++ b/packages/proto/src/lib/store.proto @@ -42,7 +42,7 @@ message HistoryResponse { enum HistoryError { NONE = 0; INVALID_CURSOR = 1; - TOO_MANY_RESULTS = 429; + TOO_MANY_REQUESTS = 429; SERVICE_UNAVAILABLE = 503; } HistoryError error = 4; From 891ed66ce563137a2ff6a41dc05dc9479cfdfcfd Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 29 Apr 2024 20:45:22 +0530 Subject: [PATCH 12/18] chore: resolve conflicts & merge (5/n) --- packages/interfaces/src/filter.ts | 10 ++--- packages/interfaces/src/message.ts | 2 +- packages/interfaces/src/protocols.ts | 2 +- packages/interfaces/src/waku.ts | 4 +- packages/sdk/src/protocols/filter.ts | 55 ++++++++++++++++++++++------ 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/packages/interfaces/src/filter.ts b/packages/interfaces/src/filter.ts index 6f0857735d..6d996bda0a 100644 --- a/packages/interfaces/src/filter.ts +++ b/packages/interfaces/src/filter.ts @@ -1,13 +1,12 @@ -import type { PeerId } from "@libp2p/interface"; - -import type { IDecodedMessage, IDecoder, SingleShardInfo } from "./message.js"; +import type { IDecodedMessage, IDecoder } from "./message.js"; import type { ContentTopic, PubsubTopic, ThisOrThat } from "./misc.js"; import type { Callback, IBaseProtocolCore, IBaseProtocolSDK, ProtocolError, - SDKProtocolResult + SDKProtocolResult, + ShardingParams } from "./protocols.js"; import type { IReceiver } from "./receiver.js"; @@ -33,8 +32,7 @@ export interface ISubscriptionSDK { export type IFilterSDK = IReceiver & IBaseProtocolSDK & { protocol: IBaseProtocolCore } & { createSubscription( - pubsubTopicShardInfo?: SingleShardInfo | PubsubTopic, - peerId?: PeerId + pubsubTopicShardInfo?: ShardingParams | PubsubTopic ): Promise; }; diff --git a/packages/interfaces/src/message.ts b/packages/interfaces/src/message.ts index 1e48030288..1c8348239e 100644 --- a/packages/interfaces/src/message.ts +++ b/packages/interfaces/src/message.ts @@ -5,7 +5,7 @@ export interface SingleShardInfo { /** * Specifying this field indicates to the encoder/decoder that static sharding must be used. */ - shard: number; + shard?: number; } export interface IRateLimitProof { diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 914b3ca14f..e2e3ca214f 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -29,7 +29,7 @@ export type IBaseProtocolSDK = { }; export type ContentTopicInfo = { - clusterId: number; + clusterId?: number; contentTopics: string[]; }; diff --git a/packages/interfaces/src/waku.ts b/packages/interfaces/src/waku.ts index a14680c4a6..5b54b0080a 100644 --- a/packages/interfaces/src/waku.ts +++ b/packages/interfaces/src/waku.ts @@ -1,5 +1,5 @@ import type { PeerId, Stream } from "@libp2p/interface"; -import type { Multiaddr } from "@multiformats/multiaddr"; +import type { MultiaddrInput } from "@multiformats/multiaddr"; import { IConnectionManager } from "./connection_manager.js"; import type { IFilterSDK } from "./filter.js"; @@ -18,7 +18,7 @@ export interface Waku { connectionManager: IConnectionManager; - dial(peer: PeerId | Multiaddr, protocols?: Protocols[]): Promise; + dial(peer: PeerId | MultiaddrInput, protocols?: Protocols[]): Promise; start(): Promise; diff --git a/packages/sdk/src/protocols/filter.ts b/packages/sdk/src/protocols/filter.ts index dd7cc5aede..988e54e24a 100644 --- a/packages/sdk/src/protocols/filter.ts +++ b/packages/sdk/src/protocols/filter.ts @@ -2,22 +2,21 @@ import type { Peer } from "@libp2p/interface"; import { FilterCore } from "@waku/core"; import { type Callback, - ContentTopic, + type ContentTopic, CoreProtocolResult, CreateSubscriptionResult, - DefaultPubsubTopic, type IAsyncIterator, type IDecodedMessage, type IDecoder, type IFilterSDK, - IProtoMessage, - ISubscriptionSDK, + type IProtoMessage, + type ISubscriptionSDK, type Libp2p, type ProtocolCreateOptions, ProtocolError, type PubsubTopic, SDKProtocolResult, - type SingleShardInfo, + type ShardingParams, type Unsubscribe } from "@waku/interfaces"; import { messageHashStr } from "@waku/message-hash"; @@ -26,7 +25,7 @@ import { ensurePubsubTopicIsConfigured, groupByContentTopic, Logger, - singleShardInfoToPubsubTopic, + shardInfoToPubsubTopics, toAsyncIterator } from "@waku/utils"; @@ -259,12 +258,12 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { * @returns The subscription object. */ async createSubscription( - pubsubTopicShardInfo: SingleShardInfo | PubsubTopic = DefaultPubsubTopic + pubsubTopicShardInfo: ShardingParams | PubsubTopic ): Promise { const pubsubTopic = typeof pubsubTopicShardInfo == "string" ? pubsubTopicShardInfo - : singleShardInfoToPubsubTopic(pubsubTopicShardInfo); + : shardInfoToPubsubTopics(pubsubTopicShardInfo)?.[0]; ensurePubsubTopicIsConfigured(pubsubTopic, this.protocol.pubsubTopics); @@ -323,10 +322,26 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { decoders: IDecoder | IDecoder[], callback: Callback ): Promise { - const { subscription } = await this.createSubscription(); - //TODO: throw will be removed when `subscribe()` is removed from IReceiver - if (!subscription) { - throw new Error("Failed to create subscription"); + const uniquePubsubTopics = this.getUniquePubsubTopics(decoders); + + if (uniquePubsubTopics.length === 0) { + throw Error( + "Failed to subscribe: no pubsubTopic found on decoders provided." + ); + } + + if (uniquePubsubTopics.length > 1) { + throw Error( + "Failed to subscribe: all decoders should have the same pubsub topic. Use createSubscription to be more agile." + ); + } + + const { subscription, error } = await this.createSubscription( + uniquePubsubTopics[0] + ); + + if (error) { + throw Error(`Failed to create subscription: ${error}`); } await subscription.subscribe(decoders, callback); @@ -347,6 +362,22 @@ class FilterSDK extends BaseProtocolSDK implements IFilterSDK { ): Promise> { return toAsyncIterator(this, decoders); } + + private getUniquePubsubTopics( + decoders: IDecoder | IDecoder[] + ): string[] { + if (!Array.isArray(decoders)) { + return [decoders.pubsubTopic]; + } + + if (decoders.length === 0) { + return []; + } + + const pubsubTopics = new Set(decoders.map((d) => d.pubsubTopic)); + + return [...pubsubTopics]; + } } export function wakuFilter( From fc1cacf1ad3f1d6c835cffa63798e08da708d79b Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Mon, 29 Apr 2024 20:45:43 +0530 Subject: [PATCH 13/18] chore: resolve conflicts & merge (6/n) --- .../core/src/lib/message/version_0.spec.ts | 185 ++++++++++-------- 1 file changed, 99 insertions(+), 86 deletions(-) diff --git a/packages/core/src/lib/message/version_0.spec.ts b/packages/core/src/lib/message/version_0.spec.ts index 4ee67ff165..4cf6856154 100644 --- a/packages/core/src/lib/message/version_0.spec.ts +++ b/packages/core/src/lib/message/version_0.spec.ts @@ -1,108 +1,97 @@ import type { IProtoMessage } from "@waku/interfaces"; +import { contentTopicToPubsubTopic } from "@waku/utils"; import { expect } from "chai"; import fc from "fast-check"; import { createDecoder, createEncoder, DecodedMessage } from "./version_0.js"; +const contentTopic = "/js-waku/1/tests/bytes"; +const pubsubTopic = contentTopicToPubsubTopic(contentTopic); + describe("Waku Message version 0", function () { it("Round trip binary serialization", async function () { await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), - fc.uint8Array({ minLength: 1 }), - async (contentTopic, pubsubTopic, payload) => { - const encoder = createEncoder({ - contentTopic - }); - const bytes = await encoder.toWire({ payload }); - const decoder = createDecoder(contentTopic); - const protoResult = await decoder.fromWireToProtoObj(bytes); - const result = (await decoder.fromProtoObj( - pubsubTopic, - protoResult! - )) as DecodedMessage; - - expect(result.contentTopic).to.eq(contentTopic); - expect(result.pubsubTopic).to.eq(pubsubTopic); - expect(result.version).to.eq(0); - expect(result.ephemeral).to.be.false; - expect(result.payload).to.deep.eq(payload); - expect(result.timestamp).to.not.be.undefined; - } - ) + fc.asyncProperty(fc.uint8Array({ minLength: 1 }), async (payload) => { + const encoder = createEncoder({ + contentTopic + }); + const bytes = await encoder.toWire({ payload }); + const decoder = createDecoder(contentTopic); + const protoResult = await decoder.fromWireToProtoObj(bytes); + const result = (await decoder.fromProtoObj( + pubsubTopic, + protoResult! + )) as DecodedMessage; + + expect(result.contentTopic).to.eq(contentTopic); + expect(result.pubsubTopic).to.eq(pubsubTopic); + expect(result.version).to.eq(0); + expect(result.ephemeral).to.be.false; + expect(result.payload).to.deep.eq(payload); + expect(result.timestamp).to.not.be.undefined; + }) ); }); it("Ephemeral field set to true", async function () { await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), - fc.uint8Array({ minLength: 1 }), - async (contentTopic, pubsubTopic, payload) => { - const encoder = createEncoder({ - contentTopic, - ephemeral: true - }); - const bytes = await encoder.toWire({ payload }); - const decoder = createDecoder(contentTopic); - const protoResult = await decoder.fromWireToProtoObj(bytes); - const result = (await decoder.fromProtoObj( - pubsubTopic, - protoResult! - )) as DecodedMessage; - - expect(result.ephemeral).to.be.true; - } - ) + fc.asyncProperty(fc.uint8Array({ minLength: 1 }), async (payload) => { + const encoder = createEncoder({ + contentTopic, + ephemeral: true + }); + const bytes = await encoder.toWire({ payload }); + const decoder = createDecoder(contentTopic); + const protoResult = await decoder.fromWireToProtoObj(bytes); + const result = (await decoder.fromProtoObj( + pubsubTopic, + protoResult! + )) as DecodedMessage; + + expect(result.ephemeral).to.be.true; + }) ); }); it("Meta field set when metaSetter is specified", async function () { await fc.assert( - fc.asyncProperty( - fc.string({ minLength: 1 }), - fc.string({ minLength: 1 }), - fc.uint8Array({ minLength: 1 }), - async (contentTopic, pubsubTopic, payload) => { - // Encode the length of the payload - // Not a relevant real life example - const metaSetter = ( - msg: IProtoMessage & { meta: undefined } - ): Uint8Array => { - const buffer = new ArrayBuffer(4); - const view = new DataView(buffer); - view.setUint32(0, msg.payload.length, false); - return new Uint8Array(buffer); - }; - - const encoder = createEncoder({ - contentTopic, - ephemeral: true, - metaSetter - }); - const bytes = await encoder.toWire({ payload }); - const decoder = createDecoder(contentTopic); - const protoResult = await decoder.fromWireToProtoObj(bytes); - const result = (await decoder.fromProtoObj( - pubsubTopic, - protoResult! - )) as DecodedMessage; - - const expectedMeta = metaSetter({ - payload, - timestamp: undefined, - contentTopic: "", - ephemeral: undefined, - meta: undefined, - rateLimitProof: undefined, - version: undefined - }); - - expect(result.meta).to.deep.eq(expectedMeta); - } - ) + fc.asyncProperty(fc.uint8Array({ minLength: 1 }), async (payload) => { + // Encode the length of the payload + // Not a relevant real life example + const metaSetter = ( + msg: IProtoMessage & { meta: undefined } + ): Uint8Array => { + const buffer = new ArrayBuffer(4); + const view = new DataView(buffer); + view.setUint32(0, msg.payload.length, false); + return new Uint8Array(buffer); + }; + + const encoder = createEncoder({ + contentTopic, + ephemeral: true, + metaSetter + }); + const bytes = await encoder.toWire({ payload }); + const decoder = createDecoder(contentTopic); + const protoResult = await decoder.fromWireToProtoObj(bytes); + const result = (await decoder.fromProtoObj( + pubsubTopic, + protoResult! + )) as DecodedMessage; + + const expectedMeta = metaSetter({ + payload, + timestamp: undefined, + contentTopic: "", + ephemeral: undefined, + meta: undefined, + rateLimitProof: undefined, + version: undefined + }); + + expect(result.meta).to.deep.eq(expectedMeta); + }) ); }); }); @@ -137,3 +126,27 @@ describe("Ensures content topic is defined", () => { expect(wrapper).to.throw("Content topic must be specified"); }); }); + +describe("Sets sharding configuration correctly", () => { + it("uses static shard pubsub topic instead of autosharding when set", async () => { + // Create an encoder setup to use autosharding + const ContentTopic = "/waku/2/content/test.js"; + const autoshardingEncoder = createEncoder({ + pubsubTopicShardInfo: { clusterId: 0 }, + contentTopic: ContentTopic + }); + + // When autosharding is enabled, we expect the shard index to be 1 + expect(autoshardingEncoder.pubsubTopic).to.be.eq("/waku/2/rs/0/1"); + + // Create an encoder setup to use static sharding with the same content topic + const singleShardInfo = { clusterId: 0, shard: 0 }; + const staticshardingEncoder = createEncoder({ + contentTopic: ContentTopic, + pubsubTopicShardInfo: singleShardInfo + }); + + // When static sharding is enabled, we expect the shard index to be 0 + expect(staticshardingEncoder.pubsubTopic).to.be.eq("/waku/2/rs/0/0"); + }); +}); From f2d6d8fa994b597d212c7db6fa6a80f4f85d1ca4 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 7 May 2024 12:21:42 +0530 Subject: [PATCH 14/18] chore: use idiomatic approach --- packages/sdk/src/protocols/filter.ts | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/sdk/src/protocols/filter.ts b/packages/sdk/src/protocols/filter.ts index 79b4ae4d93..0d169a09db 100644 --- a/packages/sdk/src/protocols/filter.ts +++ b/packages/sdk/src/protocols/filter.ts @@ -88,13 +88,9 @@ export class SubscriptionManager implements ISubscriptionSDK { const decodersGroupedByCT = groupByContentTopic(decodersArray); const contentTopics = Array.from(decodersGroupedByCT.keys()); - const promises = this.peers.map(async (peer) => { - return await this.protocol.subscribe( - this.pubsubTopic, - peer, - contentTopics - ); - }); + const promises = this.peers.map(async (peer) => + this.protocol.subscribe(this.pubsubTopic, peer, contentTopics) + ); const results = await Promise.allSettled(promises); @@ -149,9 +145,7 @@ export class SubscriptionManager implements ISubscriptionSDK { } async ping(): Promise { - const promises = this.peers.map(async (peer) => { - return await this.protocol.ping(peer); - }); + const promises = this.peers.map(async (peer) => this.protocol.ping(peer)); const results = await Promise.allSettled(promises); @@ -159,9 +153,9 @@ export class SubscriptionManager implements ISubscriptionSDK { } async unsubscribeAll(): Promise { - const promises = this.peers.map(async (peer) => { - return await this.protocol.unsubscribeAll(this.pubsubTopic, peer); - }); + const promises = this.peers.map(async (peer) => + this.protocol.unsubscribeAll(this.pubsubTopic, peer) + ); const results = await Promise.allSettled(promises); From f48c58de499b63bd9b3a12bd857f3b54afd6058d Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 7 May 2024 12:43:01 +0530 Subject: [PATCH 15/18] chore: fix tests --- .../tests/filter/single_node/subscribe.node.spec.ts | 11 ++++++++--- packages/tests/tests/filter/subscribe.node.spec.ts | 10 ++++++---- packages/tests/tests/filter/utils.ts | 10 ++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index 3a7e9bc657..896ce9a912 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -285,10 +285,15 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); try { - await subscription.subscribe(td.decoders, messageCollector.callback); - throw new Error( - `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` + const { failures, successes } = await subscription.subscribe( + td.decoders, + messageCollector.callback ); + if (failures.length === 0 || successes.length > 0) { + throw new Error( + `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` + ); + } } catch (err) { if ( err instanceof Error && diff --git a/packages/tests/tests/filter/subscribe.node.spec.ts b/packages/tests/tests/filter/subscribe.node.spec.ts index b720408357..ee248c68ec 100644 --- a/packages/tests/tests/filter/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/subscribe.node.spec.ts @@ -335,13 +335,15 @@ const runTests = (strictCheckNodes: boolean): void => { const td = generateTestData(topicCount, { pubsubTopic: TestPubsubTopic }); try { - await subscription.subscribe( + const { failures, successes } = await subscription.subscribe( td.decoders, serviceNodes.messageCollector.callback ); - throw new Error( - `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` - ); + if (failures.length === 0 || successes.length > 0) { + throw new Error( + `Subscribe to ${topicCount} topics was successful but was expected to fail with a specific error.` + ); + } } catch (err) { if ( err instanceof Error && diff --git a/packages/tests/tests/filter/utils.ts b/packages/tests/tests/filter/utils.ts index 5517ed5e7f..86b7ae7ea4 100644 --- a/packages/tests/tests/filter/utils.ts +++ b/packages/tests/tests/filter/utils.ts @@ -48,10 +48,12 @@ export async function validatePingError( subscription: ISubscriptionSDK ): Promise { try { - await subscription.ping(); - throw new Error( - "Ping was successful but was expected to fail with a specific error." - ); + const { failures, successes } = await subscription.ping(); + if (failures.length === 0 || successes.length > 0) { + throw new Error( + "Ping was successful but was expected to fail with a specific error." + ); + } } catch (err) { if ( err instanceof Error && From fd7d61ce16e517939b43b13f8ec1faaebc2ffaa1 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 7 May 2024 19:26:40 +0530 Subject: [PATCH 16/18] chore: address comments --- packages/core/src/lib/filter/index.ts | 28 ++++++++++--------- packages/tests/tests/ephemeral.node.spec.ts | 3 +- packages/tests/tests/filter/ping.node.spec.ts | 3 +- packages/tests/tests/filter/push.node.spec.ts | 6 ++-- .../single_node/multiple_pubsub.node.spec.ts | 9 ++++-- .../filter/single_node/ping.node.spec.ts | 3 +- .../filter/single_node/push.node.spec.ts | 6 ++-- .../filter/single_node/subscribe.node.spec.ts | 3 +- .../single_node/unsubscribe.node.spec.ts | 3 +- 9 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/core/src/lib/filter/index.ts b/packages/core/src/lib/filter/index.ts index 445b1167c8..b6dc724a32 100644 --- a/packages/core/src/lib/filter/index.ts +++ b/packages/core/src/lib/filter/index.ts @@ -2,7 +2,7 @@ import type { Peer, Stream } from "@libp2p/interface"; import type { IncomingStreamData } from "@libp2p/interface-internal"; import { type ContentTopic, - CoreProtocolResult, + type CoreProtocolResult, type IBaseProtocolCore, type Libp2p, type ProtocolCreateOptions, @@ -101,21 +101,23 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { contentTopics ); - const res = await pipe( - [request.encode()], - lp.encode, - stream, - lp.decode, - async (source) => await all(source) - ); - - if (!res || !res.length) { + let res: Uint8ArrayList[] | undefined; + try { + res = await pipe( + [request.encode()], + lp.encode, + stream, + lp.decode, + async (source) => await all(source) + ); + } catch (error) { + log.error("Failed to send subscribe request", error); return { + success: null, failure: { - error: ProtocolError.REMOTE_PEER_FAULT, + error: ProtocolError.GENERIC_FAIL, peerId: peer.id - }, - success: null + } }; } diff --git a/packages/tests/tests/ephemeral.node.spec.ts b/packages/tests/tests/ephemeral.node.spec.ts index 35b6850f6e..c08a4a49a1 100644 --- a/packages/tests/tests/ephemeral.node.spec.ts +++ b/packages/tests/tests/ephemeral.node.spec.ts @@ -125,7 +125,8 @@ describe("Waku Message Ephemeral field", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestEncoder.pubsubTopic); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; }); it("Ephemeral messages are not stored", async function () { diff --git a/packages/tests/tests/filter/ping.node.spec.ts b/packages/tests/tests/filter/ping.node.spec.ts index d99b659680..68287b54de 100644 --- a/packages/tests/tests/filter/ping.node.spec.ts +++ b/packages/tests/tests/filter/ping.node.spec.ts @@ -30,7 +30,8 @@ const runTests = (strictCheckNodes: boolean): void => { [serviceNodes, waku] = await runMultipleNodes(this.ctx, TestShardInfo); const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; }); afterEachCustom(this, async () => { diff --git a/packages/tests/tests/filter/push.node.spec.ts b/packages/tests/tests/filter/push.node.spec.ts index bf215ceea0..4d78c4530c 100644 --- a/packages/tests/tests/filter/push.node.spec.ts +++ b/packages/tests/tests/filter/push.node.spec.ts @@ -36,7 +36,8 @@ const runTests = (strictCheckNodes: boolean): void => { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; }); afterEachCustom(this, async () => { @@ -243,7 +244,8 @@ const runTests = (strictCheckNodes: boolean): void => { } const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; await subscription.subscribe( [TestDecoder], serviceNodes.messageCollector.callback diff --git a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts index 200ea0824d..ec8d9515dc 100644 --- a/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/filter/single_node/multiple_pubsub.node.spec.ts @@ -64,7 +64,8 @@ describe("Waku Filter V2: Multiple PubsubTopics", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(shardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); }); @@ -236,7 +237,8 @@ describe("Waku Filter V2 (Autosharding): Multiple PubsubTopics", function () { [nwaku, waku] = await runNodes(this.ctx, contentTopicInfo); const { error, subscription: _subscription } = await waku.filter.createSubscription(autoshardingPubsubTopic1); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); }); @@ -408,7 +410,8 @@ describe("Waku Filter V2 (Named sharding): Multiple PubsubTopics", function () { [nwaku, waku] = await runNodes(this.ctx, shardInfo); const { error, subscription: _subscription } = await waku.filter.createSubscription(customPubsubTopic1); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); }); diff --git a/packages/tests/tests/filter/single_node/ping.node.spec.ts b/packages/tests/tests/filter/single_node/ping.node.spec.ts index ab80ddac84..71040dfaee 100644 --- a/packages/tests/tests/filter/single_node/ping.node.spec.ts +++ b/packages/tests/tests/filter/single_node/ping.node.spec.ts @@ -32,7 +32,8 @@ describe("Waku Filter V2: Ping", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); }); diff --git a/packages/tests/tests/filter/single_node/push.node.spec.ts b/packages/tests/tests/filter/single_node/push.node.spec.ts index 2919eb535f..fdb6a75760 100644 --- a/packages/tests/tests/filter/single_node/push.node.spec.ts +++ b/packages/tests/tests/filter/single_node/push.node.spec.ts @@ -36,7 +36,8 @@ describe("Waku Filter V2: FilterPush", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(nwaku); }); @@ -225,7 +226,8 @@ describe("Waku Filter V2: FilterPush", function () { await waitForRemotePeer(waku, [Protocols.Filter, Protocols.LightPush]); const { error, subscription: _subscription } = await waku.filter.createSubscription(); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; await subscription.subscribe([TestDecoder], messageCollector.callback); await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes("M2") }); diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index 896ce9a912..a521147921 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -49,7 +49,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); await nwaku.ensureSubscriptions([TestPubsubTopic]); diff --git a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts index 2fc8c28eb0..1f7a6258a4 100644 --- a/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/unsubscribe.node.spec.ts @@ -36,7 +36,8 @@ describe("Waku Filter V2: Unsubscribe", function () { const { error, subscription: _subscription } = await waku.filter.createSubscription(TestShardInfo); - if (!error) subscription = _subscription; + if (error) throw error; + subscription = _subscription; messageCollector = new MessageCollector(); await nwaku.ensureSubscriptions([TestPubsubTopic]); }); From 0f7d3c25231affbeca330e675fd8c54f0f0f51b9 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Tue, 7 May 2024 20:11:33 +0530 Subject: [PATCH 17/18] chore: fix test --- packages/tests/src/utils/log_file.ts | 7 +++++-- .../tests/tests/filter/single_node/subscribe.node.spec.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/tests/src/utils/log_file.ts b/packages/tests/src/utils/log_file.ts index d3b55748d5..7dd10ee9d5 100644 --- a/packages/tests/src/utils/log_file.ts +++ b/packages/tests/src/utils/log_file.ts @@ -50,8 +50,11 @@ function clean(str: string): string { return str.replace(/ /g, "_").replace(/[':()/]/g, ""); } -export function makeLogFileName(ctx: Context): string { - const unitTest = ctx?.currentTest ? ctx!.currentTest : ctx.test; +export function makeLogFileName(ctx: Context | undefined): string { + if (!ctx) { + return "unknown"; + } + const unitTest = ctx.currentTest ? ctx.currentTest : ctx.test; let name = clean(unitTest!.title); let suite = unitTest?.parent; diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index a521147921..4bd1ace5fc 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -425,7 +425,7 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { }); }); - it("Subscribe and receive messages from multiple nwaku nodes", async function () { + it.only("Subscribe and receive messages from multiple nwaku nodes", async function () { await subscription.subscribe([TestDecoder], messageCollector.callback); // Set up and start a new nwaku node From 365fae0bbbe5df887bfdb32d70769b4403b550d8 Mon Sep 17 00:00:00 2001 From: danisharora099 Date: Thu, 9 May 2024 16:24:42 +0530 Subject: [PATCH 18/18] rm: only --- packages/tests/tests/filter/single_node/subscribe.node.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts index 4bd1ace5fc..a521147921 100644 --- a/packages/tests/tests/filter/single_node/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/single_node/subscribe.node.spec.ts @@ -425,7 +425,7 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () { }); }); - it.only("Subscribe and receive messages from multiple nwaku nodes", async function () { + it("Subscribe and receive messages from multiple nwaku nodes", async function () { await subscription.subscribe([TestDecoder], messageCollector.callback); // Set up and start a new nwaku node