js-waku/packages/tests/tests/relay.node.spec.ts

490 lines
15 KiB
TypeScript
Raw Normal View History

import { PeerId } from "@libp2p/interface-peer-id";
import {
createDecoder,
createEncoder,
DecodedMessage,
DefaultPubSubTopic,
waitForRemotePeer,
} from "@waku/core";
import { createRelayNode } from "@waku/create";
import type { RelayNode } from "@waku/interfaces";
2022-11-04 11:45:15 +11:00
import { Protocols } from "@waku/interfaces";
import {
createDecoder as createEciesDecoder,
createEncoder as createEciesEncoder,
2022-11-04 11:45:15 +11:00
generatePrivateKey,
getPublicKey,
} from "@waku/message-encryption/ecies";
import {
createDecoder as createSymDecoder,
createEncoder as createSymEncoder,
generateSymmetricKey,
} from "@waku/message-encryption/symmetric";
import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes";
2022-02-04 14:12:00 +11:00
import { expect } from "chai";
import debug from "debug";
2021-04-15 13:44:00 +10:00
import {
base64ToUtf8,
delay,
2021-04-15 13:44:00 +10:00
makeLogFileName,
MessageRpcResponse,
2021-04-15 13:44:00 +10:00
NOISE_KEY_1,
NOISE_KEY_2,
NOISE_KEY_3,
2022-04-01 12:19:51 +11:00
Nwaku,
} from "../src/index.js";
2022-02-04 14:12:00 +11:00
const log = debug("waku:test");
2022-02-04 14:12:00 +11:00
const TestContentTopic = "/test/1/waku-relay/utf8";
const TestEncoder = createEncoder({ contentTopic: TestContentTopic });
const TestDecoder = createDecoder(TestContentTopic);
2022-02-04 14:12:00 +11:00
describe("Waku Relay [node only]", () => {
2021-09-24 17:15:46 +10:00
// Node needed as we don't have a way to connect 2 js waku
// nodes in the browser yet
2022-02-04 14:12:00 +11:00
describe("2 js nodes", () => {
afterEach(function () {
2022-02-04 14:12:00 +11:00
if (this.currentTest?.state === "failed") {
console.log(`Test failed, log file name is ${makeLogFileName(this)}`);
}
});
let waku1: RelayNode;
let waku2: RelayNode;
beforeEach(async function () {
this.timeout(10000);
2022-02-04 14:12:00 +11:00
log("Starting JS Waku instances");
[waku1, waku2] = await Promise.all([
createRelayNode({ staticNoiseKey: NOISE_KEY_1 }).then((waku) =>
waku.start().then(() => waku)
),
createRelayNode({
staticNoiseKey: NOISE_KEY_2,
2022-02-04 14:12:00 +11:00
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
}).then((waku) => waku.start().then(() => waku)),
]);
log("Instances started, adding waku2 to waku1's address book");
await waku1.libp2p.peerStore.addressBook.set(
waku2.libp2p.peerId,
waku2.libp2p.getMultiaddrs()
);
await waku1.dial(waku2.libp2p.peerId);
2022-02-04 14:12:00 +11:00
log("Wait for mutual pubsub subscription");
await Promise.all([
waitForRemotePeer(waku1, [Protocols.Relay]),
waitForRemotePeer(waku2, [Protocols.Relay]),
]);
2022-02-04 14:12:00 +11:00
log("before each hook done");
});
afterEach(async function () {
!!waku1 &&
2022-02-04 14:12:00 +11:00
waku1.stop().catch((e) => console.log("Waku failed to stop", e));
!!waku2 &&
2022-02-04 14:12:00 +11:00
waku2.stop().catch((e) => console.log("Waku failed to stop", e));
});
2022-02-04 14:12:00 +11:00
it("Subscribe", async function () {
log("Getting subscribers");
const subscribers1 = waku1.libp2p.pubsub
.getSubscribers(DefaultPubSubTopic)
.map((p) => p.toString());
const subscribers2 = waku2.libp2p.pubsub
.getSubscribers(DefaultPubSubTopic)
.map((p) => p.toString());
2022-02-04 14:12:00 +11:00
log("Asserting mutual subscription");
expect(subscribers1).to.contain(waku2.libp2p.peerId.toString());
expect(subscribers2).to.contain(waku1.libp2p.peerId.toString());
});
2021-03-23 14:11:29 +11:00
2022-02-04 14:12:00 +11:00
it("Register correct protocols", async function () {
2023-02-09 13:21:03 +11:00
const protocols = waku1.libp2p.getProtocols();
2021-03-23 14:11:29 +11:00
2022-02-04 14:12:00 +11:00
expect(protocols).to.contain("/vac/waku/relay/2.0.0");
expect(protocols.findIndex((value) => value.match(/sub/))).to.eq(-1);
});
2021-03-23 14:11:29 +11:00
2022-02-04 14:12:00 +11:00
it("Publish", async function () {
this.timeout(10000);
2021-03-23 14:11:29 +11:00
2022-02-04 14:12:00 +11:00
const messageText = "JS to JS communication works";
const messageTimestamp = new Date("1995-12-17T03:24:00");
const message = {
payload: utf8ToBytes(messageText),
timestamp: messageTimestamp,
};
2021-03-23 14:11:29 +11:00
const receivedMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve) => {
waku2.relay.subscribe([TestDecoder], resolve);
}
);
await waku1.relay.send(TestEncoder, message);
const receivedMsg = await receivedMsgPromise;
expect(receivedMsg.contentTopic).to.eq(TestContentTopic);
expect(bytesToUtf8(receivedMsg.payload)).to.eq(messageText);
expect(receivedMsg.timestamp?.valueOf()).to.eq(
messageTimestamp.valueOf()
);
});
2022-02-04 14:12:00 +11:00
it("Filter on content topics", async function () {
this.timeout(10000);
2022-02-04 14:12:00 +11:00
const fooMessageText = "Published on content topic foo";
const barMessageText = "Published on content topic bar";
const fooContentTopic = "foo";
const barContentTopic = "bar";
const fooEncoder = createEncoder({ contentTopic: fooContentTopic });
const barEncoder = createEncoder({ contentTopic: barContentTopic });
const fooDecoder = createDecoder(fooContentTopic);
const barDecoder = createDecoder(barContentTopic);
const fooMessages: DecodedMessage[] = [];
waku2.relay.subscribe([fooDecoder], (msg) => {
fooMessages.push(msg);
});
const barMessages: DecodedMessage[] = [];
waku2.relay.subscribe([barDecoder], (msg) => {
barMessages.push(msg);
});
await waku1.relay.send(barEncoder, {
payload: utf8ToBytes(barMessageText),
});
await waku1.relay.send(fooEncoder, {
payload: utf8ToBytes(fooMessageText),
});
while (!fooMessages.length && !barMessages.length) {
await delay(100);
}
expect(fooMessages[0].contentTopic).to.eq(fooContentTopic);
expect(bytesToUtf8(fooMessages[0].payload)).to.eq(fooMessageText);
expect(barMessages[0].contentTopic).to.eq(barContentTopic);
expect(bytesToUtf8(barMessages[0].payload)).to.eq(barMessageText);
expect(fooMessages.length).to.eq(1);
expect(barMessages.length).to.eq(1);
});
2022-02-04 14:12:00 +11:00
it("Decrypt messages", async function () {
this.timeout(10000);
const asymText = "This message is encrypted using asymmetric";
const asymTopic = "/test/1/asymmetric/proto";
const symText = "This message is encrypted using symmetric encryption";
const symTopic = "/test/1/symmetric/proto";
const privateKey = generatePrivateKey();
const symKey = generateSymmetricKey();
const publicKey = getPublicKey(privateKey);
const eciesEncoder = createEciesEncoder({
contentTopic: asymTopic,
publicKey,
});
const symEncoder = createSymEncoder({
contentTopic: symTopic,
symKey,
});
const eciesDecoder = createEciesDecoder(asymTopic, privateKey);
const symDecoder = createSymDecoder(symTopic, symKey);
const msgs: DecodedMessage[] = [];
waku2.relay.subscribe([eciesDecoder], (wakuMsg) => {
msgs.push(wakuMsg);
});
waku2.relay.subscribe([symDecoder], (wakuMsg) => {
msgs.push(wakuMsg);
});
await waku1.relay.send(eciesEncoder, { payload: utf8ToBytes(asymText) });
await delay(200);
await waku1.relay.send(symEncoder, { payload: utf8ToBytes(symText) });
while (msgs.length < 2) {
await delay(200);
}
expect(msgs[0].contentTopic).to.eq(asymTopic);
expect(bytesToUtf8(msgs[0].payload!)).to.eq(asymText);
expect(msgs[1].contentTopic).to.eq(symTopic);
expect(bytesToUtf8(msgs[1].payload!)).to.eq(symText);
});
2022-02-04 14:12:00 +11:00
it("Delete observer", async function () {
this.timeout(10000);
const messageText =
2022-02-04 14:12:00 +11:00
"Published on content topic with added then deleted observer";
const contentTopic = "added-then-deleted-observer";
// The promise **fails** if we receive a message on this observer.
const receivedMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve, reject) => {
const deleteObserver = waku2.relay.subscribe(
[createDecoder(contentTopic)],
reject
) as () => void;
deleteObserver();
setTimeout(resolve, 500);
}
);
await waku1.relay.send(createEncoder({ contentTopic }), {
payload: utf8ToBytes(messageText),
});
await receivedMsgPromise;
// If it does not throw then we are good.
});
});
2022-02-04 14:12:00 +11:00
describe("Custom pubsub topic", () => {
let waku1: RelayNode;
let waku2: RelayNode;
let waku3: RelayNode;
afterEach(async function () {
!!waku1 &&
waku1.stop().catch((e) => console.log("Waku failed to stop", e));
!!waku2 &&
waku2.stop().catch((e) => console.log("Waku failed to stop", e));
!!waku3 &&
waku3.stop().catch((e) => console.log("Waku failed to stop", e));
});
2022-02-04 14:12:00 +11:00
it("Publish", async function () {
this.timeout(10000);
2022-02-04 14:12:00 +11:00
const pubSubTopic = "/some/pubsub/topic";
// 1 and 2 uses a custom pubsub
// 3 uses the default pubsub
[waku1, waku2, waku3] = await Promise.all([
createRelayNode({
pubSubTopic: pubSubTopic,
staticNoiseKey: NOISE_KEY_1,
}).then((waku) => waku.start().then(() => waku)),
createRelayNode({
pubSubTopic: pubSubTopic,
staticNoiseKey: NOISE_KEY_2,
2022-02-04 14:12:00 +11:00
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
}).then((waku) => waku.start().then(() => waku)),
createRelayNode({
staticNoiseKey: NOISE_KEY_3,
}).then((waku) => waku.start().then(() => waku)),
]);
await waku1.libp2p.peerStore.addressBook.set(
waku2.libp2p.peerId,
waku2.libp2p.getMultiaddrs()
);
await waku3.libp2p.peerStore.addressBook.set(
waku2.libp2p.peerId,
waku2.libp2p.getMultiaddrs()
);
await Promise.all([
waku1.dial(waku2.libp2p.peerId),
waku3.dial(waku2.libp2p.peerId),
]);
await Promise.all([
waitForRemotePeer(waku1, [Protocols.Relay]),
waitForRemotePeer(waku2, [Protocols.Relay]),
]);
2022-02-04 14:12:00 +11:00
const messageText = "Communicating using a custom pubsub topic";
const waku2ReceivedMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve) => {
waku2.relay.subscribe([TestDecoder], resolve);
}
);
// The promise **fails** if we receive a message on the default
// pubsub topic.
const waku3NoMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve, reject) => {
waku3.relay.subscribe([TestDecoder], reject);
setTimeout(resolve, 1000);
}
);
await waku1.relay.send(TestEncoder, {
payload: utf8ToBytes(messageText),
});
const waku2ReceivedMsg = await waku2ReceivedMsgPromise;
await waku3NoMsgPromise;
expect(bytesToUtf8(waku2ReceivedMsg.payload!)).to.eq(messageText);
expect(waku2ReceivedMsg.pubSubTopic).to.eq(pubSubTopic);
});
});
2022-04-01 12:19:51 +11:00
describe("Interop: nwaku", function () {
let waku: RelayNode;
2022-04-01 12:19:51 +11:00
let nwaku: Nwaku;
beforeEach(async function () {
this.timeout(30_000);
waku = await createRelayNode({
staticNoiseKey: NOISE_KEY_1,
});
await waku.start();
2022-04-01 12:19:51 +11:00
nwaku = new Nwaku(this.test?.ctx?.currentTest?.title + "");
feat!: implement peer exchange (#1027) * wip -- yet to test * update: draft * wip * support passing flags manually to nwaku node * refactor peer-exchange test * switch response from uint8array to ENR * rm: unnecesary logs * implement clas * fix: for loop * init-wip: directories * setup: new package & fix circular deps * bind a response handler * wip: refactor & update test * test logs * wip code - debugging * address: comments * Update packages/core/src/lib/waku_peer_exchange/peer_discovery.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * Update packages/core/src/lib/waku_peer_exchange/peer_discovery.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * address: comments * address: comments * address: comments * address: comments * address: comments * fix: test build * refactor * fix: build * comply with API * numPeers: use number instead of bigint * fix: build * Update packages/peer-exchange/package.json Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * Update packages/peer-exchange/src/waku_peer_exchange.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * Update packages/peer-exchange/src/waku_peer_exchange.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * Update packages/peer-exchange/src/waku_peer_exchange.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * address: comments, add eslint config * Update packages/peer-exchange/.eslintrc.cjs Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * Update packages/peer-exchange/src/index.ts Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * address comments * test works with test fleet * rm: only for px test => run all tests * fix: tests * reorder packages for build, and fix imports * remove: px test doesnt work with local nodes * chore: move proto into a separate package * fix: proto dir * fix: build * fix: ci * add: index for proto * fix: ci * Update packages/proto/package.json Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com> * address comments * chore: run failing test with higher timeout * chore: run failing test with higher timeout * fix: ci Co-authored-by: fryorcraken.eth <110212804+fryorcraken@users.noreply.github.com>
2022-12-07 11:35:30 +05:30
await nwaku.start({ relay: true });
2022-04-01 12:19:51 +11:00
await waku.dial(await nwaku.getMultiaddrWithId());
await waitForRemotePeer(waku, [Protocols.Relay]);
2021-03-19 15:03:31 +11:00
});
afterEach(async function () {
!!nwaku &&
nwaku.stop().catch((e) => console.log("Nwaku failed to stop", e));
2022-02-04 14:12:00 +11:00
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
});
2022-04-01 12:19:51 +11:00
it("nwaku subscribes", async function () {
let subscribers: PeerId[] = [];
while (subscribers.length === 0) {
await delay(200);
subscribers = waku.libp2p.pubsub.getSubscribers(DefaultPubSubTopic);
}
2022-04-01 12:19:51 +11:00
const nimPeerId = await nwaku.getPeerId();
expect(subscribers.map((p) => p.toString())).to.contain(
nimPeerId.toString()
);
});
2022-04-01 12:19:51 +11:00
it("Publishes to nwaku", async function () {
this.timeout(30000);
2022-02-04 14:12:00 +11:00
const messageText = "This is a message";
await waku.relay.send(TestEncoder, { payload: utf8ToBytes(messageText) });
2021-04-29 16:38:50 +10:00
let msgs: MessageRpcResponse[] = [];
while (msgs.length === 0) {
2022-02-04 14:12:00 +11:00
console.log("Waiting for messages");
await delay(200);
2022-04-01 12:19:51 +11:00
msgs = await nwaku.messages();
}
expect(msgs[0].contentTopic).to.equal(TestContentTopic);
expect(msgs[0].version).to.equal(0);
expect(base64ToUtf8(msgs[0].payload)).to.equal(messageText);
});
2022-04-01 12:19:51 +11:00
it("Nwaku publishes", async function () {
await delay(200);
2022-02-04 14:12:00 +11:00
const messageText = "Here is another message.";
const receivedMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve) => {
waku.relay.subscribe<DecodedMessage>(TestDecoder, (msg) =>
resolve(msg)
);
}
);
await nwaku.sendMessage(
Nwaku.toMessageRpcQuery({
contentTopic: TestContentTopic,
payload: utf8ToBytes(messageText),
})
);
const receivedMsg = await receivedMsgPromise;
expect(receivedMsg.contentTopic).to.eq(TestContentTopic);
expect(receivedMsg.version!).to.eq(0);
expect(bytesToUtf8(receivedMsg.payload!)).to.eq(messageText);
2021-03-19 15:03:31 +11:00
});
2021-03-25 16:39:21 +11:00
2022-04-01 12:19:51 +11:00
describe.skip("Two nodes connected to nwaku", function () {
let waku1: RelayNode;
let waku2: RelayNode;
2022-04-01 12:19:51 +11:00
let nwaku: Nwaku;
2021-03-25 16:39:21 +11:00
2021-04-20 15:07:23 +10:00
afterEach(async function () {
!!nwaku &&
nwaku.stop().catch((e) => console.log("Nwaku failed to stop", e));
!!waku1 &&
2022-02-04 14:12:00 +11:00
waku1.stop().catch((e) => console.log("Waku failed to stop", e));
!!waku2 &&
2022-02-04 14:12:00 +11:00
waku2.stop().catch((e) => console.log("Waku failed to stop", e));
2021-04-20 15:07:23 +10:00
});
2022-02-04 14:12:00 +11:00
it("Js publishes, other Js receives", async function () {
2021-04-20 15:07:23 +10:00
this.timeout(60_000);
2021-03-25 16:39:21 +11:00
[waku1, waku2] = await Promise.all([
createRelayNode({
staticNoiseKey: NOISE_KEY_1,
emitSelf: true,
}).then((waku) => waku.start().then(() => waku)),
createRelayNode({
staticNoiseKey: NOISE_KEY_2,
}).then((waku) => waku.start().then(() => waku)),
2021-03-25 16:39:21 +11:00
]);
2022-04-01 12:19:51 +11:00
nwaku = new Nwaku(makeLogFileName(this));
await nwaku.start();
2021-03-25 16:39:21 +11:00
2022-04-01 12:19:51 +11:00
const nwakuMultiaddr = await nwaku.getMultiaddrWithId();
2021-03-25 16:39:21 +11:00
await Promise.all([
2022-04-01 12:19:51 +11:00
waku1.dial(nwakuMultiaddr),
waku2.dial(nwakuMultiaddr),
2021-03-25 16:39:21 +11:00
]);
2021-04-20 10:34:23 +10:00
// Wait for identify protocol to finish
await Promise.all([
waitForRemotePeer(waku1, [Protocols.Relay]),
waitForRemotePeer(waku2, [Protocols.Relay]),
2021-03-25 16:39:21 +11:00
]);
2021-04-15 15:23:33 +10:00
2021-04-20 15:07:23 +10:00
await delay(2000);
2021-03-25 16:39:21 +11:00
// Check that the two JS peers are NOT directly connected
expect(await waku1.libp2p.peerStore.has(waku2.libp2p.peerId)).to.be
.false;
expect(waku2.libp2p.peerStore.has(waku1.libp2p.peerId)).to.be.false;
2021-03-25 16:39:21 +11:00
2022-02-04 14:12:00 +11:00
const msgStr = "Hello there!";
const message = { payload: utf8ToBytes(msgStr) };
2021-03-25 16:39:21 +11:00
const waku2ReceivedMsgPromise: Promise<DecodedMessage> = new Promise(
(resolve) => {
waku2.relay.subscribe(TestDecoder, resolve);
}
);
2021-03-25 16:39:21 +11:00
await waku1.relay.send(TestEncoder, message);
2022-02-04 14:12:00 +11:00
console.log("Waiting for message");
const waku2ReceivedMsg = await waku2ReceivedMsgPromise;
2021-03-25 16:39:21 +11:00
expect(waku2ReceivedMsg.payload).to.eq(msgStr);
2021-03-25 16:39:21 +11:00
});
});
2021-03-19 15:03:31 +11:00
});
});