fix: Wait for remote peer for Waku Relay

The promise resolves only if a remote peer is added to the gossipsub
mesh.
This commit is contained in:
Franck Royer 2022-07-25 13:13:47 +10:00 committed by fryorcraken.eth
parent 2265a0099f
commit d7b08f7e24
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
5 changed files with 72 additions and 22 deletions

41
package-lock.json generated
View File

@ -32,6 +32,7 @@
"js-sha3": "^0.8.0",
"libp2p": "next",
"multiformats": "^9.6.5",
"p-event": "^5.0.1",
"protons-runtime": "^1.0.4",
"uint8arrays": "^3.0.0",
"uuid": "^8.3.2"
@ -9798,6 +9799,31 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-event": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz",
"integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==",
"dependencies": {
"p-timeout": "^5.0.2"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-event/node_modules/p-timeout": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
"integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-fifo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",
@ -20602,6 +20628,21 @@
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz",
"integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ=="
},
"p-event": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz",
"integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==",
"requires": {
"p-timeout": "^5.0.2"
},
"dependencies": {
"p-timeout": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
"integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew=="
}
}
},
"p-fifo": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",

View File

@ -89,6 +89,7 @@
"js-sha3": "^0.8.0",
"libp2p": "next",
"multiformats": "^9.6.5",
"p-event": "^5.0.1",
"protons-runtime": "^1.0.4",
"uint8arrays": "^3.0.0",
"uuid": "^8.3.2"

View File

@ -36,7 +36,7 @@ describe("Wait for remote peer", function () {
await waku.dial(multiAddrWithId);
await delay(1000);
await waitForRemotePeer(waku, [Protocols.Relay]);
const peers = waku.relay.getPeers();
const peers = waku.relay.getMeshPeers();
const nimPeerId = multiAddrWithId.getPeerId();
expect(nimPeerId).to.not.be.undefined;
@ -64,8 +64,7 @@ describe("Wait for remote peer", function () {
await waku.dial(multiAddrWithId);
await waitPromise;
// TODO: Should getMeshPeers be used instead?
const peers = waku.relay.getPeers();
const peers = waku.relay.getMeshPeers();
const nimPeerId = multiAddrWithId.getPeerId();
expect(nimPeerId).to.not.be.undefined;

View File

@ -1,6 +1,8 @@
import type { GossipSub } from "@chainsafe/libp2p-gossipsub";
import { Peer, PeerProtocolsChangeData } from "@libp2p/interface-peer-store";
import debug from "debug";
import type { Libp2p } from "libp2p";
import { pEvent } from "p-event";
import { StoreCodecs } from "./constants";
import { Protocols, Waku } from "./waku";
@ -14,10 +16,18 @@ interface WakuProtocol {
peers: () => Promise<Peer[]>;
}
interface WakuGossipSubProtocol extends GossipSub {
getMeshPeers: () => string[];
}
/**
* Wait for a remote peer to be ready given the passed protocols.
* Useful when using the [[CreateOptions.bootstrap]] with [[Waku.create]].
*
* If the passed protocols is a GossipSub protocol, then it resolves only once
* a peer is in a mesh, to help ensure that other peers will send and receive
* message to us.
*
* @param waku The Waku Node
* @param protocols The protocols that need to be enabled by remote peers.
* @param timeoutMs A timeout value in milliseconds..
@ -34,23 +44,10 @@ export async function waitForRemotePeer(
): Promise<void> {
protocols = protocols ?? [Protocols.Relay];
const promises: Promise<void>[] = [];
const promises = [];
if (protocols.includes(Protocols.Relay)) {
const peers = waku.relay.getMeshPeers(waku.relay.pubSubTopic);
if (peers.length == 0) {
// No peer yet available, wait for a subscription
const promise = new Promise<void>((resolve) => {
// TODO: Remove listeners once done
waku.relay.addEventListener("subscription-change", () => {
// Remote peer subscribed to topic, now wait for a heartbeat
// so that the mesh is updated and the remote peer added to it
waku.relay.addEventListener("gossipsub:heartbeat", () => resolve());
});
});
promises.push(promise);
}
promises.push(waitForGossipSubPeerInMesh(waku.relay));
}
if (protocols.includes(Protocols.Store)) {
@ -105,6 +102,21 @@ async function waitForConnectedPeer(
});
}
/**
* Wait for a peer with the given protocol to be connected and in the gossipsub
* mesh.
*/
async function waitForGossipSubPeerInMesh(
waku: WakuGossipSubProtocol
): Promise<void> {
let peers = waku.getMeshPeers();
while (peers.length == 0) {
await pEvent(waku, "gossipsub:heartbeat");
peers = waku.getMeshPeers();
}
}
const awaitTimeout = (ms: number, rejectReason: string): Promise<void> =>
new Promise((_resolve, reject) => setTimeout(() => reject(rejectReason), ms));

View File

@ -210,9 +210,6 @@ export class WakuRelay extends GossipSub {
}
getMeshPeers(topic?: TopicStr): PeerIdStr[] {
return super.getMeshPeers(topic ?? DefaultPubSubTopic);
return super.getMeshPeers(topic ?? this.pubSubTopic);
}
// TODO: Implement method that uses Relay codec
// public async heartbeat(): Promise<void> {
}