mirror of https://github.com/waku-org/js-waku.git
Merge branch 'master' of github.com:waku-org/js-waku into danisharora/add-user-agent
This commit is contained in:
commit
ee009742c3
|
@ -77,16 +77,23 @@ jobs:
|
|||
node-version: ${{ env.NODE_JS }}
|
||||
- uses: bahmutov/npm-install@v1
|
||||
- run: npm run build
|
||||
- run: npm run test:node
|
||||
- run: npm run test:node > debug.log
|
||||
env:
|
||||
DEBUG: "waku:nwaku*,waku:test*"
|
||||
|
||||
- name: Upload logs on failure
|
||||
uses: actions/upload-artifact@v2
|
||||
- name: Upload debug logs on failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: debug.log
|
||||
path: debug.log
|
||||
|
||||
- name: Upload nwaku logs on failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: nwaku-logs
|
||||
path: log/
|
||||
path: packages/tests/log/
|
||||
|
||||
node_with_go_waku:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -124,16 +131,23 @@ jobs:
|
|||
|
||||
- uses: bahmutov/npm-install@v1
|
||||
- run: npm run build
|
||||
- run: npm run test:node
|
||||
- run: npm run test:node > debug.log
|
||||
env:
|
||||
DEBUG: "waku:nwaku*,waku:test*"
|
||||
|
||||
- name: Upload debug logs on failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: go-waku-debug.log
|
||||
path: debug.log
|
||||
|
||||
- name: Upload logs on failure
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: go-waku-logs
|
||||
path: log/
|
||||
path: packages/tests/log/
|
||||
|
||||
node_with_nwaku_master:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -171,13 +185,20 @@ jobs:
|
|||
./build/wakunode2 --help
|
||||
|
||||
- run: npm run build
|
||||
- run: npm run test:node
|
||||
- run: npm run test:node > debug.log
|
||||
env:
|
||||
DEBUG: "waku:nwaku*,waku:test*"
|
||||
|
||||
- name: Upload debug logs on failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: nwaku-master-debug.log
|
||||
path: debug.log
|
||||
|
||||
- name: Upload logs on failure
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: nwaku-master-logs
|
||||
path: log/
|
||||
path: packages/tests/log/
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Waku Message `ephemeral` field to mark messages as do-not-store.
|
||||
|
||||
### Changed
|
||||
|
||||
- Bumped `libp2p` to 0.40.0 and associated libp2p libraries.
|
||||
|
||||
### Removed
|
||||
|
||||
- `PeerDiscoveryStaticPeer` has been removed, use `@libp2p/bootstrap` instead.
|
||||
|
||||
## @waku/core [0.0.5](https://github.com/waku-org/js-waku/compare/@waku/core@0.0.4...@waku/core@0.0.5) (2022-11-11)
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./lib/peer_discovery_static_list": {
|
||||
"types": "./dist/lib/peer_discovery_static_list.d.ts",
|
||||
"import": "./dist/lib/peer_discovery_static_list.js"
|
||||
},
|
||||
"./lib/predefined_bootstrap_nodes": {
|
||||
"types": "./dist/lib/predefined_bootstrap_nodes.d.ts",
|
||||
"import": "./dist/lib/predefined_bootstrap_nodes.js"
|
||||
|
@ -86,23 +82,24 @@
|
|||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@waku/byte-utils": "*",
|
||||
"@chainsafe/libp2p-gossipsub": "^4.1.1",
|
||||
"@chainsafe/libp2p-gossipsub": "^5.2.1",
|
||||
"@libp2p/interface-connection": "^3.0.3",
|
||||
"@libp2p/interface-peer-discovery": "^1.0.0",
|
||||
"@libp2p/interface-peer-id": "^1.0.2",
|
||||
"@libp2p/interface-peer-info": "^1.0.1",
|
||||
"@libp2p/interface-peer-store": "^1.0.0",
|
||||
"@libp2p/interface-pubsub": "^2.0.1",
|
||||
"@libp2p/interfaces": "^3.0.2",
|
||||
"@libp2p/interface-peer-id": "^1.0.6",
|
||||
"@libp2p/interface-peer-info": "^1.0.4",
|
||||
"@libp2p/interface-peer-store": "^1.2.3",
|
||||
"@libp2p/interface-pubsub": "^3.0.1",
|
||||
"@libp2p/interface-registrar": "^2.0.4",
|
||||
"@libp2p/interfaces": "^3.0.4",
|
||||
"@libp2p/peer-id": "^1.1.10",
|
||||
"@multiformats/multiaddr": "^11.0.6",
|
||||
"@waku/byte-utils": "*",
|
||||
"@waku/interfaces": "*",
|
||||
"debug": "^4.3.4",
|
||||
"it-all": "^1.0.6",
|
||||
"it-length-prefixed": "^8.0.2",
|
||||
"it-pipe": "^2.0.4",
|
||||
"libp2p": "0.39.5",
|
||||
"libp2p": "0.40.0",
|
||||
"p-event": "^5.0.1",
|
||||
"protons-runtime": "^3.1.0",
|
||||
"uint8arraylist": "^2.3.2",
|
||||
|
|
|
@ -5,7 +5,6 @@ import json from "@rollup/plugin-json";
|
|||
export default {
|
||||
input: {
|
||||
index: "dist/index.js",
|
||||
"lib/peer_discovery_static_list": "dist/lib/peer_discovery_static_list.js",
|
||||
"lib/predefined_bootstrap_nodes": "dist/lib/predefined_bootstrap_nodes.js",
|
||||
"lib/wait_for_remote_peer": "dist/lib/wait_for_remote_peer.js",
|
||||
"lib/waku_message/version_0": "dist/lib/waku_message/version_0.js",
|
||||
|
|
|
@ -8,17 +8,17 @@ export * as waku from "./lib/waku";
|
|||
export { WakuNode } from "./lib/waku";
|
||||
|
||||
export * as waku_filter from "./lib/waku_filter";
|
||||
export { WakuFilter } from "./lib/waku_filter";
|
||||
export { wakuFilter } from "./lib/waku_filter";
|
||||
|
||||
export * as waku_light_push from "./lib/waku_light_push";
|
||||
export {
|
||||
WakuLightPush,
|
||||
wakuLightPush,
|
||||
LightPushCodec,
|
||||
PushResponse,
|
||||
} from "./lib/waku_light_push";
|
||||
|
||||
export * as waku_relay from "./lib/waku_relay";
|
||||
export { WakuRelay } from "./lib/waku_relay";
|
||||
export { wakuRelay } from "./lib/waku_relay";
|
||||
|
||||
export * as waku_store from "./lib/waku_store";
|
||||
export { PageDirection, WakuStore, StoreCodec } from "./lib/waku_store";
|
||||
export { PageDirection, wakuStore, StoreCodec } from "./lib/waku_store";
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
import type {
|
||||
PeerDiscovery,
|
||||
PeerDiscoveryEvents,
|
||||
} from "@libp2p/interface-peer-discovery";
|
||||
import { symbol } from "@libp2p/interface-peer-discovery";
|
||||
import type { PeerInfo } from "@libp2p/interface-peer-info";
|
||||
import { CustomEvent, EventEmitter } from "@libp2p/interfaces/events";
|
||||
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||
import { multiaddr } from "@multiformats/multiaddr";
|
||||
import debug from "debug";
|
||||
|
||||
import { multiaddrsToPeerInfo } from "./multiaddr_to_peer_info";
|
||||
import { getPseudoRandomSubset } from "./random_subset";
|
||||
|
||||
const log = debug("waku:peer-discovery-static-list");
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
* The maximum of peers to connect to as part of the bootstrap process.
|
||||
*
|
||||
* @default The length of the passed `peers` array.
|
||||
*/
|
||||
maxPeers?: number;
|
||||
/**
|
||||
* The interval between emitting addresses in milliseconds.
|
||||
*
|
||||
* @default {@link PeerDiscoveryStaticPeers.DefaultInterval}
|
||||
*/
|
||||
interval?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a list of multiaddr that will be used to bootstrap a node.
|
||||
*/
|
||||
export class PeerDiscoveryStaticPeers
|
||||
extends EventEmitter<PeerDiscoveryEvents>
|
||||
implements PeerDiscovery
|
||||
{
|
||||
static DefaultInterval = 200;
|
||||
private readonly peers: PeerInfo[];
|
||||
private timer?: ReturnType<typeof setInterval>;
|
||||
private readonly interval: number;
|
||||
|
||||
/**
|
||||
* @param peers Multiaddrs of peers to connect to.
|
||||
* @param opts
|
||||
*/
|
||||
constructor(peers: string[] | Multiaddr[], opts?: Options) {
|
||||
super();
|
||||
|
||||
this.interval = opts?.interval ?? PeerDiscoveryStaticPeers.DefaultInterval;
|
||||
const maxPeers = opts?.maxPeers ?? peers?.length;
|
||||
|
||||
const peerMas = peers.map((peer: string | Multiaddr) => {
|
||||
if (typeof peer === "string") {
|
||||
return multiaddr(peer);
|
||||
} else {
|
||||
return peer;
|
||||
}
|
||||
});
|
||||
this.peers = multiaddrsToPeerInfo(getPseudoRandomSubset(peerMas, maxPeers));
|
||||
log(
|
||||
"Use provided list of peers (reduced to maxPeers)",
|
||||
this.peers.map((ma) => ma.toString())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start emitting static peers.
|
||||
*/
|
||||
start(): void {
|
||||
this._startTimer();
|
||||
}
|
||||
|
||||
private _startTimer(): void {
|
||||
if (this.peers) {
|
||||
log("Starting to emit static peers.");
|
||||
if (this.timer != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.timer = setInterval(() => this._returnPeers(), this.interval);
|
||||
|
||||
this._returnPeers();
|
||||
}
|
||||
}
|
||||
|
||||
_returnPeers(): void {
|
||||
if (this.timer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.peers.forEach((peerData) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent<PeerInfo>("peer", { detail: peerData })
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop emitting peers.
|
||||
*/
|
||||
stop(): void {
|
||||
if (this.timer != null) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
|
||||
this.timer = undefined;
|
||||
}
|
||||
|
||||
get [symbol](): true {
|
||||
return true;
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag](): string {
|
||||
return "@waku/peer-discovery-static-list";
|
||||
}
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||
import { multiaddr } from "@multiformats/multiaddr";
|
||||
|
||||
import { getPseudoRandomSubset } from "./random_subset";
|
||||
|
||||
export const DefaultWantedNumber = 1;
|
||||
|
@ -23,7 +20,7 @@ export enum Fleet {
|
|||
export function getPredefinedBootstrapNodes(
|
||||
fleet: Fleet = Fleet.Prod,
|
||||
wantedNumber: number = DefaultWantedNumber
|
||||
): Multiaddr[] {
|
||||
): string[] {
|
||||
if (wantedNumber <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
@ -42,7 +39,6 @@ export function getPredefinedBootstrapNodes(
|
|||
|
||||
nodes = Object.values(nodes) as string[];
|
||||
|
||||
nodes = nodes.map((node: string) => multiaddr(node));
|
||||
return getPseudoRandomSubset(nodes, wantedNumber);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,13 +94,13 @@ async function waitForConnectedPeer(
|
|||
for (const codec of codecs) {
|
||||
if (evt.detail.protocols.includes(codec)) {
|
||||
log("Resolving for", codec, evt.detail.protocols);
|
||||
waku.libp2p.peerStore.removeEventListener("change:protocols", cb);
|
||||
waku.peerStore.removeEventListener("change:protocols", cb);
|
||||
resolve();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
waku.libp2p.peerStore.addEventListener("change:protocols", cb);
|
||||
waku.peerStore.addEventListener("change:protocols", cb);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import type { Stream } from "@libp2p/interface-connection";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import type { PubSub } from "@libp2p/interface-pubsub";
|
||||
import { peerIdFromString } from "@libp2p/peer-id";
|
||||
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||
import { multiaddr } from "@multiformats/multiaddr";
|
||||
import type { Waku } from "@waku/interfaces";
|
||||
import type { Filter, LightPush, Relay, Store, Waku } from "@waku/interfaces";
|
||||
import { Protocols } from "@waku/interfaces";
|
||||
import debug from "debug";
|
||||
import type { Libp2p } from "libp2p";
|
||||
|
||||
import { FilterCodec, WakuFilter } from "./waku_filter";
|
||||
import { LightPushCodec, WakuLightPush } from "./waku_light_push";
|
||||
import { FilterCodec, FilterComponents } from "./waku_filter";
|
||||
import { LightPushCodec, LightPushComponents } from "./waku_light_push";
|
||||
import { EncoderV0 } from "./waku_message/version_0";
|
||||
import { WakuRelay } from "./waku_relay";
|
||||
import * as relayConstants from "./waku_relay/constants";
|
||||
import { RelayCodecs, RelayPingContentTopic } from "./waku_relay/constants";
|
||||
import { StoreCodec, WakuStore } from "./waku_store";
|
||||
import { StoreCodec, StoreComponents } from "./waku_store";
|
||||
|
||||
export const DefaultPingKeepAliveValueSecs = 0;
|
||||
export const DefaultRelayKeepAliveValueSecs = 5 * 60;
|
||||
|
@ -47,10 +44,10 @@ export interface WakuOptions {
|
|||
|
||||
export class WakuNode implements Waku {
|
||||
public libp2p: Libp2p;
|
||||
public relay?: WakuRelay;
|
||||
public store?: WakuStore;
|
||||
public filter?: WakuFilter;
|
||||
public lightPush?: WakuLightPush;
|
||||
public relay?: Relay;
|
||||
public store?: Store;
|
||||
public filter?: Filter;
|
||||
public lightPush?: LightPush;
|
||||
|
||||
private pingKeepAliveTimers: {
|
||||
[peer: string]: ReturnType<typeof setInterval>;
|
||||
|
@ -62,16 +59,26 @@ export class WakuNode implements Waku {
|
|||
constructor(
|
||||
options: WakuOptions,
|
||||
libp2p: Libp2p,
|
||||
store?: WakuStore,
|
||||
lightPush?: WakuLightPush,
|
||||
filter?: WakuFilter
|
||||
store?: (components: StoreComponents) => Store,
|
||||
lightPush?: (components: LightPushComponents) => LightPush,
|
||||
filter?: (components: FilterComponents) => Filter
|
||||
) {
|
||||
this.libp2p = libp2p;
|
||||
this.store = store;
|
||||
this.filter = filter;
|
||||
this.lightPush = lightPush;
|
||||
|
||||
if (isWakuRelay(libp2p.pubsub)) {
|
||||
const { peerStore, connectionManager, registrar } = libp2p;
|
||||
const components = { peerStore, connectionManager, registrar };
|
||||
|
||||
if (store) {
|
||||
this.store = store(components);
|
||||
}
|
||||
if (filter) {
|
||||
this.filter = filter(components);
|
||||
}
|
||||
if (lightPush) {
|
||||
this.lightPush = lightPush(components);
|
||||
}
|
||||
|
||||
if (isRelay(libp2p.pubsub)) {
|
||||
this.relay = libp2p.pubsub;
|
||||
}
|
||||
|
||||
|
@ -109,6 +116,15 @@ export class WakuNode implements Waku {
|
|||
libp2p.connectionManager.addEventListener("peer:disconnect", (evt) => {
|
||||
this.stopKeepAlive(evt.detail.remotePeer);
|
||||
});
|
||||
|
||||
// Trivial handling of discovered peers, to be refined.
|
||||
libp2p.addEventListener("peer:discovery", (evt) => {
|
||||
const peerId = evt.detail.id;
|
||||
log(`Found peer ${peerId.toString()}, dialing.`);
|
||||
libp2p.dial(peerId).catch((err) => {
|
||||
log(`Fail to dial ${peerId}`, err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,29 +163,6 @@ export class WakuNode implements Waku {
|
|||
return this.libp2p.dialProtocol(peer, codecs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add peer to address book, it will be auto-dialed in the background.
|
||||
*/
|
||||
async addPeerToAddressBook(
|
||||
peerId: PeerId | string,
|
||||
multiaddrs: Multiaddr[] | string[]
|
||||
): Promise<void> {
|
||||
let peer;
|
||||
if (typeof peerId === "string") {
|
||||
peer = peerIdFromString(peerId);
|
||||
} else {
|
||||
peer = peerId;
|
||||
}
|
||||
const addresses = multiaddrs.map((addr: Multiaddr | string) => {
|
||||
if (typeof addr === "string") {
|
||||
return multiaddr(addr);
|
||||
} else {
|
||||
return addr;
|
||||
}
|
||||
});
|
||||
await this.libp2p.peerStore.addressBook.set(peer, addresses);
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
await this.libp2p.start();
|
||||
}
|
||||
|
@ -255,7 +248,7 @@ export class WakuNode implements Waku {
|
|||
}
|
||||
}
|
||||
|
||||
function isWakuRelay(pubsub: PubSub): pubsub is WakuRelay {
|
||||
function isRelay(pubsub: PubSub): pubsub is Relay {
|
||||
if (pubsub) {
|
||||
try {
|
||||
return pubsub.multicodecs.includes(
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import type { Stream } from "@libp2p/interface-connection";
|
||||
import type { ConnectionManager } from "@libp2p/interface-connection-manager";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import type { PeerStore } from "@libp2p/interface-peer-store";
|
||||
import type { Peer } from "@libp2p/interface-peer-store";
|
||||
import type { IncomingStreamData } from "@libp2p/interface-registrar";
|
||||
import type { Registrar } from "@libp2p/interface-registrar";
|
||||
import type {
|
||||
Callback,
|
||||
DecodedMessage,
|
||||
|
@ -14,7 +17,6 @@ import debug from "debug";
|
|||
import all from "it-all";
|
||||
import * as lp from "it-length-prefixed";
|
||||
import { pipe } from "it-pipe";
|
||||
import type { Libp2p } from "libp2p";
|
||||
|
||||
import { WakuMessage as WakuMessageProto } from "../../proto/message";
|
||||
import { DefaultPubSubTopic } from "../constants";
|
||||
|
@ -28,12 +30,19 @@ import {
|
|||
import { toProtoMessage } from "../to_proto_message";
|
||||
|
||||
import { ContentFilter, FilterRPC } from "./filter_rpc";
|
||||
|
||||
export { ContentFilter };
|
||||
|
||||
export const FilterCodec = "/vac/waku/filter/2.0.0-beta1";
|
||||
|
||||
const log = debug("waku:filter");
|
||||
|
||||
export interface FilterComponents {
|
||||
peerStore: PeerStore;
|
||||
registrar: Registrar;
|
||||
connectionManager: ConnectionManager;
|
||||
}
|
||||
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
|
||||
|
@ -55,7 +64,7 @@ export type UnsubscribeFunction = () => Promise<void>;
|
|||
* - https://github.com/status-im/go-waku/issues/245
|
||||
* - https://github.com/status-im/nwaku/issues/948
|
||||
*/
|
||||
export class WakuFilter implements Filter {
|
||||
class WakuFilter implements Filter {
|
||||
pubSubTopic: string;
|
||||
private subscriptions: Map<string, Callback<any>>;
|
||||
private decoders: Map<
|
||||
|
@ -63,11 +72,11 @@ export class WakuFilter implements Filter {
|
|||
Set<Decoder<any>>
|
||||
>;
|
||||
|
||||
constructor(public libp2p: Libp2p, options?: CreateOptions) {
|
||||
constructor(public components: FilterComponents, options?: CreateOptions) {
|
||||
this.subscriptions = new Map();
|
||||
this.decoders = new Map();
|
||||
this.pubSubTopic = options?.pubSubTopic ?? DefaultPubSubTopic;
|
||||
this.libp2p
|
||||
this.components.registrar
|
||||
.handle(FilterCodec, this.onRequest.bind(this))
|
||||
.catch((e) => log("Failed to register filter protocol", e));
|
||||
}
|
||||
|
@ -139,6 +148,10 @@ export class WakuFilter implements Filter {
|
|||
};
|
||||
}
|
||||
|
||||
get peerStore(): PeerStore {
|
||||
return this.components.peerStore;
|
||||
}
|
||||
|
||||
private onRequest(streamData: IncomingStreamData): void {
|
||||
log("Receiving message push");
|
||||
try {
|
||||
|
@ -261,7 +274,9 @@ export class WakuFilter implements Filter {
|
|||
}
|
||||
|
||||
private async newStream(peer: Peer): Promise<Stream> {
|
||||
const connections = this.libp2p.connectionManager.getConnections(peer.id);
|
||||
const connections = this.components.connectionManager.getConnections(
|
||||
peer.id
|
||||
);
|
||||
const connection = selectConnection(connections);
|
||||
if (!connection) {
|
||||
throw new Error("Failed to get a connection to the peer");
|
||||
|
@ -272,7 +287,7 @@ export class WakuFilter implements Filter {
|
|||
|
||||
private async getPeer(peerId?: PeerId): Promise<Peer> {
|
||||
const res = await selectPeerForProtocol(
|
||||
this.libp2p.peerStore,
|
||||
this.components.peerStore,
|
||||
[FilterCodec],
|
||||
peerId
|
||||
);
|
||||
|
@ -283,10 +298,16 @@ export class WakuFilter implements Filter {
|
|||
}
|
||||
|
||||
async peers(): Promise<Peer[]> {
|
||||
return getPeersForProtocol(this.libp2p.peerStore, [FilterCodec]);
|
||||
return getPeersForProtocol(this.components.peerStore, [FilterCodec]);
|
||||
}
|
||||
|
||||
async randomPeer(): Promise<Peer | undefined> {
|
||||
return selectRandomPeer(await this.peers());
|
||||
}
|
||||
}
|
||||
|
||||
export function wakuFilter(
|
||||
init: Partial<CreateOptions> = {}
|
||||
): (components: FilterComponents) => Filter {
|
||||
return (components: FilterComponents) => new WakuFilter(components, init);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { ConnectionManager } from "@libp2p/interface-connection-manager";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import type { Peer } from "@libp2p/interface-peer-store";
|
||||
import type { PeerStore } from "@libp2p/interface-peer-store";
|
||||
import type {
|
||||
Encoder,
|
||||
LightPush,
|
||||
Message,
|
||||
ProtocolOptions,
|
||||
SendResult,
|
||||
|
@ -10,7 +13,6 @@ import debug from "debug";
|
|||
import all from "it-all";
|
||||
import * as lp from "it-length-prefixed";
|
||||
import { pipe } from "it-pipe";
|
||||
import { Libp2p } from "libp2p";
|
||||
import { Uint8ArrayList } from "uint8arraylist";
|
||||
|
||||
import { PushResponse } from "../../proto/light_push";
|
||||
|
@ -29,6 +31,11 @@ const log = debug("waku:light-push");
|
|||
export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
|
||||
export { PushResponse };
|
||||
|
||||
export interface LightPushComponents {
|
||||
peerStore: PeerStore;
|
||||
connectionManager: ConnectionManager;
|
||||
}
|
||||
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
|
||||
|
@ -44,10 +51,10 @@ export interface CreateOptions {
|
|||
/**
|
||||
* Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
|
||||
*/
|
||||
export class WakuLightPush {
|
||||
class WakuLightPush implements LightPush {
|
||||
pubSubTopic: string;
|
||||
|
||||
constructor(public libp2p: Libp2p, options?: CreateOptions) {
|
||||
constructor(public components: LightPushComponents, options?: CreateOptions) {
|
||||
this.pubSubTopic = options?.pubSubTopic ?? DefaultPubSubTopic;
|
||||
}
|
||||
|
||||
|
@ -59,7 +66,7 @@ export class WakuLightPush {
|
|||
const pubSubTopic = opts?.pubSubTopic ? opts.pubSubTopic : this.pubSubTopic;
|
||||
|
||||
const res = await selectPeerForProtocol(
|
||||
this.libp2p.peerStore,
|
||||
this.components.peerStore,
|
||||
[LightPushCodec],
|
||||
opts?.peerId
|
||||
);
|
||||
|
@ -69,7 +76,9 @@ export class WakuLightPush {
|
|||
}
|
||||
const { peer } = res;
|
||||
|
||||
const connections = this.libp2p.connectionManager.getConnections(peer.id);
|
||||
const connections = this.components.connectionManager.getConnections(
|
||||
peer.id
|
||||
);
|
||||
const connection = selectConnection(connections);
|
||||
|
||||
if (!connection) throw "Failed to get a connection to the peer";
|
||||
|
@ -123,7 +132,7 @@ export class WakuLightPush {
|
|||
* peers.
|
||||
*/
|
||||
async peers(): Promise<Peer[]> {
|
||||
return getPeersForProtocol(this.libp2p.peerStore, [LightPushCodec]);
|
||||
return getPeersForProtocol(this.components.peerStore, [LightPushCodec]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,4 +143,15 @@ export class WakuLightPush {
|
|||
async randomPeer(): Promise<Peer | undefined> {
|
||||
return selectRandomPeer(await this.peers());
|
||||
}
|
||||
|
||||
get peerStore(): PeerStore {
|
||||
return this.components.peerStore;
|
||||
}
|
||||
}
|
||||
|
||||
export function wakuLightPush(
|
||||
init: Partial<CreateOptions> = {}
|
||||
): (components: LightPushComponents) => LightPush {
|
||||
return (components: LightPushComponents) =>
|
||||
new WakuLightPush(components, init);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ describe("Waku Message version 0", function () {
|
|||
);
|
||||
});
|
||||
|
||||
it("Ephemeral", async function () {
|
||||
it("Ephemeral field set to true", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(fc.uint8Array({ minLength: 1 }), async (payload) => {
|
||||
const encoder = new EncoderV0(TestContentTopic, true);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
GossipSub,
|
||||
GossipSubComponents,
|
||||
GossipsubMessage,
|
||||
GossipsubOpts,
|
||||
} from "@chainsafe/libp2p-gossipsub";
|
||||
|
@ -55,7 +56,7 @@ export type CreateOptions = {
|
|||
*
|
||||
* @implements {require('libp2p-interfaces/src/pubsub')}
|
||||
*/
|
||||
export class WakuRelay extends GossipSub implements Relay {
|
||||
class WakuRelay extends GossipSub implements Relay {
|
||||
pubSubTopic: string;
|
||||
defaultDecoder: Decoder<DecodedMessage>;
|
||||
public static multicodec: string = constants.RelayCodecs[0];
|
||||
|
@ -66,13 +67,16 @@ export class WakuRelay extends GossipSub implements Relay {
|
|||
*/
|
||||
public observers: Map<string, Set<Observer<any>>>;
|
||||
|
||||
constructor(options?: Partial<CreateOptions>) {
|
||||
constructor(
|
||||
components: GossipSubComponents,
|
||||
options?: Partial<CreateOptions>
|
||||
) {
|
||||
options = Object.assign(options ?? {}, {
|
||||
// Ensure that no signature is included nor expected in the messages.
|
||||
globalSignaturePolicy: SignaturePolicy.StrictNoSign,
|
||||
fallbackToFloodsub: false,
|
||||
});
|
||||
super(options);
|
||||
super(components, options);
|
||||
this.multicodecs = constants.RelayCodecs;
|
||||
|
||||
this.observers = new Map();
|
||||
|
@ -188,3 +192,9 @@ export class WakuRelay extends GossipSub implements Relay {
|
|||
}
|
||||
|
||||
WakuRelay.multicodec = constants.RelayCodecs[constants.RelayCodecs.length - 1];
|
||||
|
||||
export function wakuRelay(
|
||||
init: Partial<CreateOptions> = {}
|
||||
): (components: GossipSubComponents) => Relay {
|
||||
return (components: GossipSubComponents) => new WakuRelay(components, init);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import type { Connection } from "@libp2p/interface-connection";
|
||||
import type { ConnectionManager } from "@libp2p/interface-connection-manager";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import { Peer } from "@libp2p/interface-peer-store";
|
||||
import { DecodedMessage, Decoder } from "@waku/interfaces";
|
||||
import type { Peer, PeerStore } from "@libp2p/interface-peer-store";
|
||||
import { DecodedMessage, Decoder, Store } from "@waku/interfaces";
|
||||
import debug from "debug";
|
||||
import all from "it-all";
|
||||
import * as lp from "it-length-prefixed";
|
||||
import { pipe } from "it-pipe";
|
||||
import { Libp2p } from "libp2p";
|
||||
import { Uint8ArrayList } from "uint8arraylist";
|
||||
|
||||
import * as proto from "../../proto/store";
|
||||
|
@ -27,6 +27,11 @@ export const DefaultPageSize = 10;
|
|||
|
||||
export { PageDirection };
|
||||
|
||||
export interface StoreComponents {
|
||||
peerStore: PeerStore;
|
||||
connectionManager: ConnectionManager;
|
||||
}
|
||||
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
|
||||
|
@ -82,10 +87,10 @@ export interface QueryOptions {
|
|||
*
|
||||
* The Waku Store protocol can be used to retrieved historical messages.
|
||||
*/
|
||||
export class WakuStore {
|
||||
class WakuStore implements Store {
|
||||
pubSubTopic: string;
|
||||
|
||||
constructor(public libp2p: Libp2p, options?: CreateOptions) {
|
||||
constructor(public components: StoreComponents, options?: CreateOptions) {
|
||||
this.pubSubTopic = options?.pubSubTopic ?? DefaultPubSubTopic;
|
||||
}
|
||||
|
||||
|
@ -232,7 +237,7 @@ export class WakuStore {
|
|||
});
|
||||
|
||||
const res = await selectPeerForProtocol(
|
||||
this.libp2p.peerStore,
|
||||
this.components.peerStore,
|
||||
[StoreCodec],
|
||||
options?.peerId
|
||||
);
|
||||
|
@ -242,7 +247,9 @@ export class WakuStore {
|
|||
}
|
||||
const { peer, protocol } = res;
|
||||
|
||||
const connections = this.libp2p.connectionManager.getConnections(peer.id);
|
||||
const connections = this.components.connectionManager.getConnections(
|
||||
peer.id
|
||||
);
|
||||
const connection = selectConnection(connections);
|
||||
|
||||
if (!connection) throw "Failed to get a connection to the peer";
|
||||
|
@ -262,7 +269,11 @@ export class WakuStore {
|
|||
* store protocol. Waku may or may not be currently connected to these peers.
|
||||
*/
|
||||
async peers(): Promise<Peer[]> {
|
||||
return getPeersForProtocol(this.libp2p.peerStore, [StoreCodec]);
|
||||
return getPeersForProtocol(this.components.peerStore, [StoreCodec]);
|
||||
}
|
||||
|
||||
get peerStore(): PeerStore {
|
||||
return this.components.peerStore;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,3 +381,9 @@ async function* paginate<T extends DecodedMessage>(
|
|||
export function isDefined<T>(msg: T | undefined): msg is T {
|
||||
return !!msg;
|
||||
}
|
||||
|
||||
export function wakuStore(
|
||||
init: Partial<CreateOptions> = {}
|
||||
): (components: StoreComponents) => Store {
|
||||
return (components: StoreComponents) => new WakuStore(components, init);
|
||||
}
|
||||
|
|
|
@ -50,12 +50,13 @@
|
|||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/libp2p-noise": "^10.1.0",
|
||||
"@libp2p/bootstrap": "^5.0.0",
|
||||
"@libp2p/interface-peer-discovery": "^1.0.2",
|
||||
"@libp2p/mplex": "^7.0.0",
|
||||
"@libp2p/websockets": "^5.0.0",
|
||||
"@waku/core": "*",
|
||||
"@waku/interfaces": "*",
|
||||
"@chainsafe/libp2p-noise": "^8.0.1",
|
||||
"@libp2p/interface-peer-discovery": "^1.0.0",
|
||||
"@libp2p/mplex": "^5.1.1",
|
||||
"@libp2p/websockets": "^3.0.3"
|
||||
"@waku/interfaces": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^22.0.0",
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import { Noise } from "@chainsafe/libp2p-noise";
|
||||
import { noise } from "@chainsafe/libp2p-noise";
|
||||
import { bootstrap } from "@libp2p/bootstrap";
|
||||
import type { PeerDiscovery } from "@libp2p/interface-peer-discovery";
|
||||
import { Mplex } from "@libp2p/mplex";
|
||||
import { WebSockets } from "@libp2p/websockets";
|
||||
import { mplex } from "@libp2p/mplex";
|
||||
import { webSockets } from "@libp2p/websockets";
|
||||
import { all as filterAll } from "@libp2p/websockets/filters";
|
||||
import {
|
||||
waku,
|
||||
waku_relay,
|
||||
WakuFilter,
|
||||
WakuLightPush,
|
||||
wakuFilter,
|
||||
wakuLightPush,
|
||||
WakuNode,
|
||||
WakuRelay,
|
||||
WakuStore,
|
||||
wakuRelay,
|
||||
wakuStore,
|
||||
} from "@waku/core";
|
||||
import { DefaultUserAgent } from "@waku/core";
|
||||
import { PeerDiscoveryStaticPeers } from "@waku/core/lib/peer_discovery_static_list";
|
||||
import { getPredefinedBootstrapNodes } from "@waku/core/lib/predefined_bootstrap_nodes";
|
||||
import type { WakuFull, WakuLight, WakuPrivacy } from "@waku/interfaces";
|
||||
import type { Relay, WakuFull, WakuLight, WakuPrivacy } from "@waku/interfaces";
|
||||
import type { Libp2p } from "libp2p";
|
||||
import { createLibp2p, Libp2pOptions } from "libp2p";
|
||||
import type { Components } from "libp2p/components";
|
||||
|
||||
type WakuOptions = waku.WakuOptions;
|
||||
type RelayCreateOptions = waku_relay.CreateOptions;
|
||||
|
@ -78,16 +79,16 @@ export async function createLightNode(
|
|||
options?.userAgent
|
||||
);
|
||||
|
||||
const wakuStore = new WakuStore(libp2p, options);
|
||||
const wakuLightPush = new WakuLightPush(libp2p, options);
|
||||
const wakuFilter = new WakuFilter(libp2p, options);
|
||||
const store = wakuStore(options);
|
||||
const lightPush = wakuLightPush(options);
|
||||
const filter = wakuFilter(options);
|
||||
|
||||
return new WakuNode(
|
||||
options ?? {},
|
||||
libp2p,
|
||||
wakuStore,
|
||||
wakuLightPush,
|
||||
wakuFilter
|
||||
store,
|
||||
lightPush,
|
||||
filter
|
||||
) as WakuLight;
|
||||
}
|
||||
|
||||
|
@ -106,7 +107,7 @@ export async function createPrivacyNode(
|
|||
}
|
||||
|
||||
const libp2p = await defaultLibp2p(
|
||||
new WakuRelay(options),
|
||||
wakuRelay(options),
|
||||
libp2pOptions,
|
||||
options?.userAgent
|
||||
);
|
||||
|
@ -138,38 +139,40 @@ export async function createFullNode(
|
|||
}
|
||||
|
||||
const libp2p = await defaultLibp2p(
|
||||
new WakuRelay(options),
|
||||
wakuRelay(options),
|
||||
libp2pOptions,
|
||||
options?.userAgent
|
||||
);
|
||||
|
||||
const wakuStore = new WakuStore(libp2p, options);
|
||||
const wakuLightPush = new WakuLightPush(libp2p, options);
|
||||
const wakuFilter = new WakuFilter(libp2p, options);
|
||||
const store = wakuStore(options);
|
||||
const lightPush = wakuLightPush(options);
|
||||
const filter = wakuFilter(options);
|
||||
|
||||
return new WakuNode(
|
||||
options ?? {},
|
||||
libp2p,
|
||||
wakuStore,
|
||||
wakuLightPush,
|
||||
wakuFilter
|
||||
store,
|
||||
lightPush,
|
||||
filter
|
||||
) as WakuFull;
|
||||
}
|
||||
|
||||
export function defaultPeerDiscovery(): PeerDiscovery {
|
||||
return new PeerDiscoveryStaticPeers(getPredefinedBootstrapNodes());
|
||||
export function defaultPeerDiscovery(): (
|
||||
components: Components
|
||||
) => PeerDiscovery {
|
||||
return bootstrap({ list: getPredefinedBootstrapNodes() });
|
||||
}
|
||||
|
||||
export async function defaultLibp2p(
|
||||
wakuRelay?: WakuRelay,
|
||||
wakuRelay?: (components: Components) => Relay,
|
||||
options?: Partial<Libp2pOptions>,
|
||||
userAgent?: string
|
||||
): Promise<Libp2p> {
|
||||
const libp2pOpts = Object.assign(
|
||||
{
|
||||
transports: [new WebSockets({ filter: filterAll })],
|
||||
streamMuxers: [new Mplex()],
|
||||
connectionEncryption: [new Noise()],
|
||||
transports: [webSockets({ filter: filterAll })],
|
||||
streamMuxers: [mplex()],
|
||||
connectionEncryption: [noise()],
|
||||
identify: {
|
||||
host: {
|
||||
agentVersion: userAgent ?? DefaultUserAgent,
|
||||
|
|
|
@ -48,12 +48,12 @@
|
|||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/libp2p-gossipsub": "^4.1.1",
|
||||
"@chainsafe/libp2p-gossipsub": "^5.2.1",
|
||||
"@libp2p/interface-connection": "^3.0.2",
|
||||
"@libp2p/interface-peer-id": "^1.0.5",
|
||||
"@libp2p/interface-peer-store": "^1.2.2",
|
||||
"@libp2p/interface-peer-store": "^1.2.3",
|
||||
"@multiformats/multiaddr": "^11.0.6",
|
||||
"libp2p": "0.39.5"
|
||||
"libp2p": "0.40.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { GossipSub } from "@chainsafe/libp2p-gossipsub";
|
|||
import type { Stream } from "@libp2p/interface-connection";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import type { Peer } from "@libp2p/interface-peer-store";
|
||||
import type { PeerStore } from "@libp2p/interface-peer-store";
|
||||
import type { Multiaddr } from "@multiformats/multiaddr";
|
||||
import type { Libp2p } from "libp2p";
|
||||
|
||||
|
@ -13,7 +14,7 @@ export enum Protocols {
|
|||
}
|
||||
|
||||
export interface PointToPointProtocol {
|
||||
libp2p: Libp2p;
|
||||
peerStore: PeerStore;
|
||||
peers: () => Promise<Peer[]>;
|
||||
}
|
||||
|
||||
|
@ -112,11 +113,6 @@ export interface Waku {
|
|||
|
||||
dial(peer: PeerId | Multiaddr, protocols?: Protocols[]): Promise<Stream>;
|
||||
|
||||
addPeerToAddressBook(
|
||||
peerId: PeerId | string,
|
||||
multiaddrs: Multiaddr[] | string[]
|
||||
): void;
|
||||
|
||||
start(): Promise<void>;
|
||||
|
||||
stop(): Promise<void>;
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"pretest": "run-s pretest:*",
|
||||
"pretest:1-init-git-submodules": "[ -f '../../nwaku/build/wakunode2' ] || git submodule update --init --recursive",
|
||||
"pretest:2-build-nwaku": "[ -f '../../nwaku/build/wakunode2' ] || run-s nwaku:build",
|
||||
"nwaku:build": "(PROC=$(nproc --all 2>/dev/null || echo 2); cd ../../nwaku; make -j$PROC update; NIMFLAGS=\"-d:chronicles_colors=off -d:chronicles_sinks=textlines -d:chronicles_log_level=TRACE\" make -j$PROC wakunode2)",
|
||||
"nwaku:build": "(PROC=$(nproc --all 2>/dev/null || echo 2); cd ../../nwaku; make -j$PROC update; NIMFLAGS=\"-d:chronicles_colors=off -d:chronicles_sinks=textlines\" make -j$PROC wakunode2)",
|
||||
"nwaku:force-build": "(cd ../../nwaku && rm -rf ./build/ ./vendor) && run-s nwaku:build",
|
||||
"check": "run-s check:*",
|
||||
"check:prettier": "prettier . --list-different",
|
||||
|
@ -55,14 +55,15 @@
|
|||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@waku/core": "*",
|
||||
"@waku/enr": "*",
|
||||
"@waku/create": "*",
|
||||
"@waku/interfaces": "*",
|
||||
"@waku/byte-utils": "*",
|
||||
"@waku/core": "*",
|
||||
"@waku/create": "*",
|
||||
"@waku/enr": "*",
|
||||
"@waku/interfaces": "*",
|
||||
"@waku/message-encryption": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@libp2p/bootstrap": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||
"@typescript-eslint/parser": "^5.8.1",
|
||||
"cspell": "^5.14.0",
|
||||
|
|
|
@ -164,6 +164,8 @@ export class Nwaku {
|
|||
args
|
||||
);
|
||||
|
||||
process.env.WAKUNODE2_STORE_MESSAGE_DB_URL = "";
|
||||
|
||||
const argsArray = argsToArray(mergedArgs);
|
||||
if (WAKU_SERVICE_NODE_PARAMS) {
|
||||
argsArray.push(WAKU_SERVICE_NODE_PARAMS);
|
||||
|
@ -442,8 +444,7 @@ export function defaultArgs(): Args {
|
|||
rpc: true,
|
||||
rpcAdmin: true,
|
||||
websocketSupport: true,
|
||||
storeMessageDbUrl: "sqlite://:memory:",
|
||||
logLevel: LogLevel.Debug,
|
||||
logLevel: LogLevel.Trace,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
import { bytesToUtf8, utf8ToBytes } from "@waku/byte-utils";
|
||||
import { waitForRemotePeer } from "@waku/core/lib/wait_for_remote_peer";
|
||||
import { DecoderV0, EncoderV0 } from "@waku/core/lib/waku_message/version_0";
|
||||
import { createFullNode, createLightNode } from "@waku/create";
|
||||
import { DecodedMessage, Protocols, WakuLight } from "@waku/interfaces";
|
||||
import {
|
||||
AsymDecoder,
|
||||
AsymEncoder,
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
SymDecoder,
|
||||
SymEncoder,
|
||||
} from "@waku/message-encryption";
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
|
||||
import { makeLogFileName, NOISE_KEY_1, NOISE_KEY_2, Nwaku } from "../src";
|
||||
import { delay } from "../src/delay";
|
||||
|
||||
const log = debug("waku:test:ephemeral");
|
||||
|
||||
const TestContentTopic = "/test/1/ephemeral/utf8";
|
||||
const TestEncoder = new EncoderV0(TestContentTopic);
|
||||
const TestDecoder = new DecoderV0(TestContentTopic);
|
||||
|
||||
describe("Waku Message Ephemeral field", () => {
|
||||
let waku: WakuLight;
|
||||
let nwaku: Nwaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nwaku && nwaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
beforeEach(async function () {
|
||||
this.timeout(15000);
|
||||
nwaku = new Nwaku(makeLogFileName(this));
|
||||
await nwaku.start({ filter: true, lightpush: true, store: 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);
|
||||
});
|
||||
|
||||
it("Ephemeral messages are not stored", async function () {
|
||||
this.timeout(15_000);
|
||||
|
||||
const asymText =
|
||||
"This message is encrypted for me using asymmetric encryption";
|
||||
const symText =
|
||||
"This message is encrypted for me using symmetric encryption";
|
||||
const clearText = "This is a clear text message";
|
||||
|
||||
const asymMsg = { payload: utf8ToBytes(asymText) };
|
||||
const symMsg = {
|
||||
payload: utf8ToBytes(symText),
|
||||
};
|
||||
const clearMsg = {
|
||||
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 = new AsymEncoder(
|
||||
AsymContentTopic,
|
||||
publicKey,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const symEncoder = new SymEncoder(SymContentTopic, symKey, undefined, true);
|
||||
const clearEncoder = new EncoderV0(TestContentTopic, true);
|
||||
|
||||
const asymDecoder = new AsymDecoder(AsymContentTopic, privateKey);
|
||||
const symDecoder = new SymDecoder(SymContentTopic, symKey);
|
||||
|
||||
const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([
|
||||
createFullNode({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
}).then((waku) => waku.start().then(() => waku)),
|
||||
createFullNode({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
}).then((waku) => waku.start().then(() => waku)),
|
||||
nwaku.getMultiaddrWithId(),
|
||||
]);
|
||||
|
||||
log("Waku nodes created");
|
||||
|
||||
await Promise.all([
|
||||
waku1.dial(nimWakuMultiaddr),
|
||||
waku2.dial(nimWakuMultiaddr),
|
||||
]);
|
||||
|
||||
log("Waku nodes connected to nwaku");
|
||||
|
||||
await waitForRemotePeer(waku1, [Protocols.LightPush]);
|
||||
|
||||
log("Sending messages using light push");
|
||||
await Promise.all([
|
||||
waku1.lightPush.push(asymEncoder, asymMsg),
|
||||
waku1.lightPush.push(symEncoder, symMsg),
|
||||
waku1.lightPush.push(clearEncoder, clearMsg),
|
||||
]);
|
||||
|
||||
await waitForRemotePeer(waku2, [Protocols.Store]);
|
||||
|
||||
const messages: DecodedMessage[] = [];
|
||||
log("Retrieve messages from store");
|
||||
|
||||
for await (const msgPromises of waku2.store.queryGenerator([
|
||||
asymDecoder,
|
||||
symDecoder,
|
||||
TestDecoder,
|
||||
])) {
|
||||
for (const promise of msgPromises) {
|
||||
const msg = await promise;
|
||||
if (msg) {
|
||||
messages.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(messages?.length).eq(0);
|
||||
|
||||
!!waku1 && waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it("Ephemeral field is preserved - encoder v0", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const ephemeralEncoder = new EncoderV0(TestContentTopic, true);
|
||||
|
||||
const messages: DecodedMessage[] = [];
|
||||
const callback = (msg: DecodedMessage): void => {
|
||||
messages.push(msg);
|
||||
};
|
||||
await waku.filter.subscribe([TestDecoder], callback);
|
||||
|
||||
await delay(200);
|
||||
const normalTxt = "Normal message";
|
||||
const ephemeralTxt = "Ephemeral Message";
|
||||
await waku.lightPush.push(TestEncoder, {
|
||||
payload: utf8ToBytes(normalTxt),
|
||||
});
|
||||
await waku.lightPush.push(ephemeralEncoder, {
|
||||
payload: utf8ToBytes(ephemeralTxt),
|
||||
});
|
||||
while (messages.length < 2) {
|
||||
await delay(250);
|
||||
}
|
||||
|
||||
const normalMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === normalTxt
|
||||
);
|
||||
const ephemeralMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === ephemeralTxt
|
||||
);
|
||||
|
||||
expect(normalMsg).to.not.be.undefined;
|
||||
expect(ephemeralMsg).to.not.be.undefined;
|
||||
|
||||
expect(normalMsg!.ephemeral).to.be.false;
|
||||
expect(ephemeralMsg!.ephemeral).to.be.true;
|
||||
});
|
||||
|
||||
it("Ephemeral field is preserved - symmetric encryption", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
const ephemeralEncoder = new SymEncoder(
|
||||
TestContentTopic,
|
||||
symKey,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const encoder = new SymEncoder(TestContentTopic, symKey);
|
||||
const decoder = new SymDecoder(TestContentTopic, symKey);
|
||||
|
||||
const messages: DecodedMessage[] = [];
|
||||
const callback = (msg: DecodedMessage): void => {
|
||||
messages.push(msg);
|
||||
};
|
||||
await waku.filter.subscribe([decoder], callback);
|
||||
|
||||
await delay(200);
|
||||
const normalTxt = "Normal message";
|
||||
const ephemeralTxt = "Ephemeral Message";
|
||||
await waku.lightPush.push(encoder, {
|
||||
payload: utf8ToBytes(normalTxt),
|
||||
});
|
||||
await waku.lightPush.push(ephemeralEncoder, {
|
||||
payload: utf8ToBytes(ephemeralTxt),
|
||||
});
|
||||
while (messages.length < 2) {
|
||||
await delay(250);
|
||||
}
|
||||
|
||||
const normalMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === normalTxt
|
||||
);
|
||||
const ephemeralMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === ephemeralTxt
|
||||
);
|
||||
|
||||
expect(normalMsg).to.not.be.undefined;
|
||||
expect(ephemeralMsg).to.not.be.undefined;
|
||||
|
||||
expect(normalMsg!.ephemeral).to.be.false;
|
||||
expect(ephemeralMsg!.ephemeral).to.be.true;
|
||||
});
|
||||
|
||||
it("Ephemeral field is preserved - asymmetric encryption", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const privKey = generatePrivateKey();
|
||||
const pubKey = getPublicKey(privKey);
|
||||
|
||||
const ephemeralEncoder = new AsymEncoder(
|
||||
TestContentTopic,
|
||||
pubKey,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const encoder = new AsymEncoder(TestContentTopic, pubKey);
|
||||
const decoder = new AsymDecoder(TestContentTopic, privKey);
|
||||
|
||||
const messages: DecodedMessage[] = [];
|
||||
const callback = (msg: DecodedMessage): void => {
|
||||
messages.push(msg);
|
||||
};
|
||||
await waku.filter.subscribe([decoder], callback);
|
||||
|
||||
await delay(200);
|
||||
const normalTxt = "Normal message";
|
||||
const ephemeralTxt = "Ephemeral Message";
|
||||
await waku.lightPush.push(encoder, {
|
||||
payload: utf8ToBytes(normalTxt),
|
||||
});
|
||||
await waku.lightPush.push(ephemeralEncoder, {
|
||||
payload: utf8ToBytes(ephemeralTxt),
|
||||
});
|
||||
while (messages.length < 2) {
|
||||
await delay(250);
|
||||
}
|
||||
|
||||
const normalMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === normalTxt
|
||||
);
|
||||
const ephemeralMsg = messages.find(
|
||||
(msg) => bytesToUtf8(msg.payload!) === ephemeralTxt
|
||||
);
|
||||
|
||||
expect(normalMsg).to.not.be.undefined;
|
||||
expect(ephemeralMsg).to.not.be.undefined;
|
||||
|
||||
expect(normalMsg!.ephemeral).to.be.false;
|
||||
expect(ephemeralMsg!.ephemeral).to.be.true;
|
||||
});
|
||||
});
|
|
@ -16,8 +16,7 @@ describe("nwaku", () => {
|
|||
"--rpc=true",
|
||||
"--rpc-admin=true",
|
||||
"--websocket-support=true",
|
||||
"--store-message-db-url=sqlite://:memory:",
|
||||
"--log-level=DEBUG",
|
||||
"--log-level=TRACE",
|
||||
"--ports-shift=42",
|
||||
];
|
||||
|
||||
|
|
|
@ -64,10 +64,11 @@ describe("Waku Relay [node only]", () => {
|
|||
}).then((waku) => waku.start().then(() => waku)),
|
||||
]);
|
||||
log("Instances started, adding waku2 to waku1's address book");
|
||||
waku1.addPeerToAddressBook(
|
||||
await waku1.libp2p.peerStore.addressBook.set(
|
||||
waku2.libp2p.peerId,
|
||||
waku2.libp2p.getMultiaddrs()
|
||||
);
|
||||
await waku1.dial(waku2.libp2p.peerId);
|
||||
|
||||
log("Wait for mutual pubsub subscription");
|
||||
await Promise.all([
|
||||
|
@ -281,14 +282,18 @@ describe("Waku Relay [node only]", () => {
|
|||
}).then((waku) => waku.start().then(() => waku)),
|
||||
]);
|
||||
|
||||
waku1.addPeerToAddressBook(
|
||||
await waku1.libp2p.peerStore.addressBook.set(
|
||||
waku2.libp2p.peerId,
|
||||
waku2.libp2p.getMultiaddrs()
|
||||
);
|
||||
waku3.addPeerToAddressBook(
|
||||
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]),
|
||||
|
|
|
@ -18,6 +18,7 @@ import { expect } from "chai";
|
|||
import debug from "debug";
|
||||
|
||||
import { makeLogFileName, NOISE_KEY_1, NOISE_KEY_2, Nwaku } from "../src";
|
||||
import { delay } from "../src/delay";
|
||||
|
||||
const log = debug("waku:test:store");
|
||||
|
||||
|
@ -204,6 +205,7 @@ describe("Waku Store", () => {
|
|||
})
|
||||
)
|
||||
).to.be.true;
|
||||
await delay(1); // to ensure each timestamp is unique.
|
||||
}
|
||||
|
||||
waku = await createFullNode({
|
||||
|
@ -242,6 +244,7 @@ describe("Waku Store", () => {
|
|||
})
|
||||
)
|
||||
).to.be.true;
|
||||
await delay(1); // to ensure each timestamp is unique.
|
||||
}
|
||||
|
||||
waku = await createFullNode({
|
||||
|
@ -369,143 +372,6 @@ describe("Waku Store", () => {
|
|||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it.skip("Ephemeral support", async function () {
|
||||
this.timeout(15_000);
|
||||
|
||||
const asymText = "This message is encrypted for me using asymmetric";
|
||||
const asymTopic = "/test/1/asymmetric/proto";
|
||||
|
||||
const symText =
|
||||
"This message is encrypted for me using symmetric encryption";
|
||||
const symTopic = "/test/1/symmetric/proto";
|
||||
|
||||
const clearText = "This is a clear text message for everyone to read";
|
||||
|
||||
const storeReadableText = "This message is readable by the store";
|
||||
const storeUnreadableText = "This message is not readable by the store";
|
||||
|
||||
const timestamp = new Date();
|
||||
|
||||
const asymMsg = { payload: utf8ToBytes(asymText), timestamp };
|
||||
const symMsg = {
|
||||
payload: utf8ToBytes(symText),
|
||||
timestamp: new Date(timestamp.valueOf() + 1),
|
||||
};
|
||||
const clearMsg = {
|
||||
payload: utf8ToBytes(clearText),
|
||||
timestamp: new Date(timestamp.valueOf() + 2),
|
||||
};
|
||||
|
||||
const storeReadableMsg = {
|
||||
payload: utf8ToBytes(storeReadableText),
|
||||
};
|
||||
const storeUnreadableMsg = {
|
||||
payload: utf8ToBytes(storeUnreadableText),
|
||||
};
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const symKey = generateSymmetricKey();
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
|
||||
const storeWithAsymEncoder = new AsymEncoder(
|
||||
asymTopic,
|
||||
publicKey,
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
const storeWithSymEncoder = new SymEncoder(
|
||||
symTopic,
|
||||
symKey,
|
||||
undefined,
|
||||
false
|
||||
);
|
||||
|
||||
const dontStoreWithAsymEncoder = new AsymEncoder(
|
||||
asymTopic,
|
||||
publicKey,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const dontStoreWithSymEncoder = new SymEncoder(
|
||||
symTopic,
|
||||
symKey,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
const storeEncoder = new EncoderV0(TestContentTopic, false);
|
||||
const storeUnreadableEncoder = new EncoderV0(TestContentTopic, true);
|
||||
|
||||
const asymDecoder = new AsymDecoder(asymTopic, privateKey);
|
||||
const symDecoder = new SymDecoder(symTopic, symKey);
|
||||
|
||||
const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([
|
||||
createFullNode({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
}).then((waku) => waku.start().then(() => waku)),
|
||||
createFullNode({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
}).then((waku) => waku.start().then(() => waku)),
|
||||
nwaku.getMultiaddrWithId(),
|
||||
]);
|
||||
|
||||
log("Waku nodes created");
|
||||
|
||||
await Promise.all([
|
||||
waku1.dial(nimWakuMultiaddr),
|
||||
waku2.dial(nimWakuMultiaddr),
|
||||
]);
|
||||
|
||||
log("Waku nodes connected to nwaku");
|
||||
|
||||
await waitForRemotePeer(waku1, [Protocols.LightPush]);
|
||||
|
||||
log("Sending messages using light push");
|
||||
await Promise.all([
|
||||
waku1.lightPush.push(storeWithAsymEncoder, asymMsg),
|
||||
waku1.lightPush.push(storeWithSymEncoder, symMsg),
|
||||
waku1.lightPush.push(dontStoreWithAsymEncoder, asymMsg),
|
||||
waku1.lightPush.push(dontStoreWithSymEncoder, symMsg),
|
||||
waku1.lightPush.push(TestEncoder, clearMsg),
|
||||
waku1.lightPush.push(storeEncoder, storeReadableMsg),
|
||||
waku1.lightPush.push(storeUnreadableEncoder, storeUnreadableMsg),
|
||||
]);
|
||||
|
||||
await waitForRemotePeer(waku2, [Protocols.Store]);
|
||||
|
||||
const messages: DecodedMessage[] = [];
|
||||
log("Retrieve messages from store");
|
||||
|
||||
for await (const msgPromises of waku2.store.queryGenerator([
|
||||
asymDecoder,
|
||||
symDecoder,
|
||||
TestDecoder,
|
||||
])) {
|
||||
for (const promise of msgPromises) {
|
||||
const msg = await promise;
|
||||
if (msg) {
|
||||
messages.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Messages are ordered from oldest to latest within a page (1 page query)
|
||||
expect(bytesToUtf8(messages[0].payload!)).to.eq(asymText);
|
||||
expect(bytesToUtf8(messages[1].payload!)).to.eq(symText);
|
||||
expect(bytesToUtf8(messages[2].payload!)).to.eq(clearText);
|
||||
expect(bytesToUtf8(messages[3].payload!)).to.eq(storeReadableText);
|
||||
expect(messages?.length).eq(4);
|
||||
|
||||
// check for ephemeral
|
||||
expect(messages[0].ephemeral).to.be.false;
|
||||
expect(messages[1].ephemeral).to.be.false;
|
||||
expect(messages[2].ephemeral).to.be.false;
|
||||
expect(messages[3].ephemeral).to.be.false;
|
||||
|
||||
!!waku1 && waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it("Ordered callback, using start and end time", async function () {
|
||||
this.timeout(20000);
|
||||
|
||||
|
@ -599,6 +465,7 @@ describe("Waku Store", () => {
|
|||
})
|
||||
)
|
||||
).to.be.true;
|
||||
await delay(1); // to ensure each timestamp is unique.
|
||||
}
|
||||
|
||||
waku = await createFullNode({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { bootstrap } from "@libp2p/bootstrap";
|
||||
import type { PeerId } from "@libp2p/interface-peer-id";
|
||||
import { bytesToUtf8, utf8ToBytes } from "@waku/byte-utils";
|
||||
import { DefaultUserAgent } from "@waku/core";
|
||||
import { PeerDiscoveryStaticPeers } from "@waku/core/lib/peer_discovery_static_list";
|
||||
import { waitForRemotePeer } from "@waku/core/lib/wait_for_remote_peer";
|
||||
import { createLightNode, createPrivacyNode } from "@waku/create";
|
||||
import type {
|
||||
|
@ -72,7 +72,7 @@ describe("Waku Dial [node only]", function () {
|
|||
waku = await createLightNode({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
peerDiscovery: [new PeerDiscoveryStaticPeers([multiAddrWithId])],
|
||||
peerDiscovery: [bootstrap({ list: [multiAddrWithId.toString()] })],
|
||||
},
|
||||
});
|
||||
await waku.start();
|
||||
|
@ -95,12 +95,12 @@ describe("Waku Dial [node only]", function () {
|
|||
nwaku = new Nwaku(makeLogFileName(this));
|
||||
await nwaku.start();
|
||||
|
||||
const nwakuMa = await nwaku.getMultiaddrWithId();
|
||||
|
||||
waku = await createLightNode({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
peerDiscovery: [
|
||||
new PeerDiscoveryStaticPeers([await nwaku.getMultiaddrWithId()]),
|
||||
],
|
||||
peerDiscovery: [bootstrap({ list: [nwakuMa.toString()] })],
|
||||
},
|
||||
});
|
||||
await waku.start();
|
||||
|
@ -141,10 +141,11 @@ describe("Decryption Keys", () => {
|
|||
}).then((waku) => waku.start().then(() => waku)),
|
||||
]);
|
||||
|
||||
waku1.addPeerToAddressBook(
|
||||
await waku1.libp2p.peerStore.addressBook.set(
|
||||
waku2.libp2p.peerId,
|
||||
waku2.libp2p.getMultiaddrs()
|
||||
);
|
||||
await waku1.dial(waku2.libp2p.peerId);
|
||||
|
||||
await Promise.all([
|
||||
waitForRemotePeer(waku1, [Protocols.Relay]),
|
||||
|
@ -212,7 +213,7 @@ describe("User Agent", () => {
|
|||
}).then((waku) => waku.start().then(() => waku)),
|
||||
]);
|
||||
|
||||
waku1.addPeerToAddressBook(
|
||||
await waku1.libp2p.peerStore.addressBook.set(
|
||||
waku2.libp2p.peerId,
|
||||
waku2.libp2p.getMultiaddrs()
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue