Skip to content

Commit 11881c8

Browse files
raykyrijoeltg
andauthored
packages/gossiplog: Set up webrtc for browser target, update associated packages (#501)
* packages/gossiplog: add browser libp2p target with webrtc * packages/bootstrap-peer: add maxRegistrationTTL and maxDiscoverLimit config options * packages/gossiplog: update browser libp2p config * packages/relay-server: update relay server config * packages/test-network: add client-webrtc * packages/test-network: update README.md * packages/test-network: fix d3 error finally * packages/test-network: remove self:peer:update in client-webrtc * packages/test-network: show non-mesh connections as dotted lines * packages/gossiplog: add @libp2p/circuit-relay-v2 * packages/gossiplog: set reservation ttl to 60s in the browser * packages/test-network: adjust params * packages/test-network: add server-side eventsource, move events and reduce to shared file * packages/test-network: upgrade versions for npm packages in dockerfiles * packages/test-network: better state handling and refreshing across sessions * packages/test-network: consolidate internal imports * packages/bootstrap-peer: upgrade @canvas-js/libp2p-rendezvous, add discoverFilter * packages/relay-server: update testnet config * packages/gossiplog: set DHT to client mode in browser, manually connect to all discovered peers * packages/test-network: add worker socket system * packages/test-network: update padding * packages/test-network: remove nodes belonging to worker when worker closes * packages/test-network: add autospawn * packages/test-network: move Dockerfiles into folders --------- Co-authored-by: Joel Gustafson <[email protected]>
1 parent 3cd1c09 commit 11881c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2153
-1094
lines changed

package-lock.json

Lines changed: 594 additions & 716 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bootstrap-peer/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
},
1515
"exports": {
1616
".": "./lib/index.js",
17-
"./libp2p": "./lib/libp2p.js"
17+
"./libp2p": "./lib/libp2p.js",
18+
"./api": "./lib/api.js"
1819
},
1920
"dependencies": {
20-
"@canvas-js/libp2p-rendezvous": "^0.4.5",
21+
"@canvas-js/libp2p-rendezvous": "^0.5.2",
2122
"@chainsafe/libp2p-noise": "^16.1.3",
2223
"@chainsafe/libp2p-yamux": "^7.0.1",
2324
"@ipld/dag-cbor": "^9.2.4",

packages/bootstrap-peer/src/config.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,44 @@ import process from "node:process"
33
import { PrivateKey } from "@libp2p/interface"
44
import { generateKeyPair, privateKeyFromProtobuf } from "@libp2p/crypto/keys"
55

6-
const { DATABASE_PATH, LIBP2P_PRIVATE_KEY, LISTEN, ANNOUNCE, MAX_CONNECTIONS } = process.env
6+
const {
7+
DATABASE_PATH,
8+
LIBP2P_PRIVATE_KEY,
9+
LISTEN,
10+
ANNOUNCE,
11+
MAX_CONNECTIONS,
12+
MAX_DISCOVER_LIMIT,
13+
MAX_REGISTRATION_TTL,
14+
} = process.env
715

816
export interface Config {
917
path: string | null
1018
privateKey: PrivateKey
1119
listen: string[]
1220
announce: string[]
1321
maxConnections: number
22+
23+
maxRegistrationTTL?: number
24+
maxDiscoverLimit?: number
1425
}
1526

1627
export async function getConfig(config: Partial<Config>): Promise<Config> {
17-
const path = DATABASE_PATH ?? null
28+
const path = config.path ?? DATABASE_PATH ?? null
1829

1930
let privateKey = config.privateKey
2031
if (privateKey === undefined) {
2132
privateKey = await getPrivateKey()
2233
}
2334

24-
let { maxConnections = 1024 } = config
25-
if (MAX_CONNECTIONS !== undefined) maxConnections = parseInt(MAX_CONNECTIONS)
35+
let { maxConnections = 1024, maxRegistrationTTL, maxDiscoverLimit } = config
36+
if (MAX_CONNECTIONS !== undefined) maxConnections ??= parseInt(MAX_CONNECTIONS)
37+
if (MAX_REGISTRATION_TTL !== undefined) maxRegistrationTTL ??= parseInt(MAX_REGISTRATION_TTL)
38+
if (MAX_DISCOVER_LIMIT !== undefined) maxDiscoverLimit ??= parseInt(MAX_DISCOVER_LIMIT)
2639

2740
const listen = config.listen ?? LISTEN?.split(",") ?? ["/ip4/127.0.0.1/tcp/8080/ws"]
2841
const announce = config.announce ?? ANNOUNCE?.split(",") ?? []
2942

30-
return { path, privateKey, listen, announce, maxConnections }
43+
return { path, privateKey, listen, announce, maxConnections, maxRegistrationTTL, maxDiscoverLimit }
3144
}
3245

3346
async function getPrivateKey(): Promise<PrivateKey> {

packages/bootstrap-peer/src/libp2p.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@ import { webSockets } from "@libp2p/websockets"
33
import { yamux } from "@chainsafe/libp2p-yamux"
44
import { noise } from "@chainsafe/libp2p-noise"
55
import { Identify, identify } from "@libp2p/identify"
6-
import { PingService, ping } from "@libp2p/ping"
6+
import { Ping, ping } from "@libp2p/ping"
77
import { prometheusMetrics } from "@libp2p/prometheus-metrics"
88
import { peerIdFromPrivateKey } from "@libp2p/peer-id"
9+
import { Multiaddr } from "@multiformats/multiaddr"
910

1011
import { rendezvousServer, RendezvousServer } from "@canvas-js/libp2p-rendezvous/server"
1112

1213
import { Config, getConfig } from "./config.js"
1314

1415
export type ServiceMap = {
1516
identify: Identify
16-
ping: PingService
17+
ping: Ping
1718
rendezvous: RendezvousServer
1819
}
1920

20-
export const maxRegistrationTTL = 2 * 60 * 60 // 2h
21+
const defaultMaxRegistrationTTL = 2 * 60 * 60 // 2h
22+
const defaultMaxDiscoverLimit = 64
23+
24+
const isWebRTC = (addr: Multiaddr) => addr.protoNames().slice(-3).join("/") === "p2p-circuit/webrtc/p2p"
2125

2226
export async function getLibp2p(config: Partial<Config> = {}) {
2327
const { path, privateKey, listen, announce, maxConnections } = await getConfig(config)
@@ -34,14 +38,17 @@ export async function getLibp2p(config: Partial<Config> = {}) {
3438
announce.map((addr) => `${addr}/p2p/${peerId}`),
3539
)
3640

41+
const maxRegistrationTTL = config.maxRegistrationTTL ?? defaultMaxRegistrationTTL
42+
const maxDiscoverLimit = config.maxDiscoverLimit ?? defaultMaxDiscoverLimit
43+
3744
const libp2p = await createLibp2p<ServiceMap>({
3845
privateKey: privateKey,
3946
start: false,
4047
addresses: { listen, announce },
4148
transports: [webSockets({})],
4249
connectionGater: { denyDialMultiaddr: (addr) => false },
4350
connectionManager: { maxConnections },
44-
connectionMonitor: { enabled: false, protocolPrefix: "canvas" },
51+
connectionMonitor: { enabled: true, protocolPrefix: "canvas" },
4552

4653
peerStore: {
4754
maxAddressAge: maxRegistrationTTL * 1000,
@@ -56,7 +63,21 @@ export async function getLibp2p(config: Partial<Config> = {}) {
5663
services: {
5764
identify: identify({ protocolPrefix: "canvas" }),
5865
ping: ping({ protocolPrefix: "canvas" }),
59-
rendezvous: rendezvousServer({ path, maxRegistrationTTL }),
66+
rendezvous: rendezvousServer({
67+
path,
68+
maxRegistrationTTL,
69+
maxDiscoverLimit,
70+
discoverFilter: (namespace, peerId, multiaddrs) => {
71+
if (multiaddrs.some(isWebRTC)) {
72+
const connections = libp2p.getConnections(peerId)
73+
if (connections.length === 0) {
74+
return false
75+
}
76+
}
77+
78+
return true
79+
},
80+
}),
6081
},
6182
})
6283

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"any-signal": "^4.1.1",
6060
"chalk": "^5.4.1",
6161
"cors": "^2.8.5",
62-
"esbuild": "^0.24.2",
62+
"esbuild": "^0.25.5",
6363
"esbuild-wasm": "^0.25.1",
6464
"ethers": "^6.13.5",
6565
"express": "^5.1.0",

packages/gossiplog/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
"node": "./lib/targets/node/index.js",
3737
"react-native": "./lib/targets/react-native/index.js",
3838
"default": "./lib/targets/default/index.js"
39+
},
40+
"#target/libp2p": {
41+
"browser": "./lib/targets/browser/libp2p.js",
42+
"node": "./lib/targets/node/libp2p.js",
43+
"react-native": "./lib/targets/react-native/libp2p.js",
44+
"default": "./lib/targets/default/libp2p.js"
3945
}
4046
},
4147
"scripts": {
@@ -46,7 +52,7 @@
4652
},
4753
"dependencies": {
4854
"@canvas-js/interfaces": "0.16.0-next.3",
49-
"@canvas-js/libp2p-rendezvous": "^0.4.5",
55+
"@canvas-js/libp2p-rendezvous": "^0.5.2",
5056
"@canvas-js/modeldb": "0.16.0-next.3",
5157
"@canvas-js/modeldb-durable-objects": "0.16.0-next.3",
5258
"@canvas-js/modeldb-idb": "0.16.0-next.3",
@@ -63,6 +69,8 @@
6369
"@chainsafe/libp2p-yamux": "^7.0.1",
6470
"@ipld/dag-cbor": "^9.2.4",
6571
"@ipld/dag-json": "^10.2.5",
72+
"@libp2p/bootstrap": "^11.0.39",
73+
"@libp2p/circuit-relay-v2": "^3.2.15",
6674
"@libp2p/crypto": "^5.1.5",
6775
"@libp2p/identify": "^3.0.33",
6876
"@libp2p/interface": "^2.10.3",
@@ -73,6 +81,7 @@
7381
"@libp2p/peer-id": "^5.1.6",
7482
"@libp2p/ping": "^2.0.33",
7583
"@libp2p/prometheus-metrics": "^4.3.22",
84+
"@libp2p/webrtc": "^5.2.16",
7685
"@libp2p/websockets": "^9.2.14",
7786
"@multiformats/multiaddr": "^12.4.1",
7887
"@noble/hashes": "^1.8.0",

packages/gossiplog/src/AbstractGossipLog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import type {
1515
import { ed25519, prepareMessage } from "@canvas-js/signatures"
1616
import { assert, zip } from "@canvas-js/utils"
1717

18-
import { NetworkConfig, ServiceMap } from "@canvas-js/gossiplog/libp2p"
1918
import { NetworkClient } from "@canvas-js/gossiplog/client"
19+
import { NetworkConfig, ServiceMap } from "@canvas-js/gossiplog/libp2p"
2020
import { AbortError, MessageNotFoundError, MissingParentError } from "@canvas-js/gossiplog/errors"
2121
import * as sync from "@canvas-js/gossiplog/sync"
2222

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
export * from "./libp2p.js"
1+
export { getLibp2p } from "#target/libp2p"
2+
3+
export * from "./interface.js"
24
export * from "./service.js"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { MultiaddrConnection, PrivateKey, PubSub } from "@libp2p/interface"
2+
import type { Identify } from "@libp2p/identify"
3+
import type { KadDHT } from "@libp2p/kad-dht"
4+
import type { Ping } from "@libp2p/ping"
5+
import type { GossipsubEvents } from "@chainsafe/libp2p-gossipsub"
6+
export type { GossipSub } from "@chainsafe/libp2p-gossipsub"
7+
import type { Multiaddr } from "@multiformats/multiaddr"
8+
import type { Registry } from "prom-client"
9+
10+
import type { RendezvousClient } from "@canvas-js/libp2p-rendezvous/client"
11+
12+
import type { GossipLogService } from "./service.js"
13+
14+
export interface NetworkConfig {
15+
/** start libp2p on initialization (default: true) */
16+
start?: boolean
17+
privateKey?: PrivateKey
18+
19+
/** array of local WebSocket multiaddrs, e.g. "/ip4/127.0.0.1/tcp/3000/ws" */
20+
listen?: string[]
21+
22+
/** array of public WebSocket multiaddrs, e.g. "/dns4/myapp.com/tcp/443/wss" */
23+
announce?: string[]
24+
25+
bootstrapList?: string[]
26+
relayServer?: string
27+
denyDialMultiaddr?(multiaddr: Multiaddr): Promise<boolean> | boolean
28+
denyInboundConnection?(maConn: MultiaddrConnection): Promise<boolean> | boolean
29+
30+
maxConnections?: number
31+
registry?: Registry
32+
}
33+
34+
export type ServiceMap<Payload> = {
35+
identify: Identify
36+
ping: Ping
37+
pubsub: PubSub<GossipsubEvents>
38+
gossipLog: GossipLogService<Payload>
39+
dht: KadDHT
40+
rendezvous: RendezvousClient
41+
}

packages/gossiplog/src/targets/browser/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { NetworkClient } from "@canvas-js/gossiplog/client"
44
import { assert } from "@canvas-js/utils"
55

66
import type { PlatformTarget } from "../interface.js"
7+
import { getLibp2p } from "./libp2p.js"
8+
import { getPrivateKey } from "./privateKey.js"
79

810
const target: PlatformTarget = {
911
async connect(gossipLog, url, options = {}) {
@@ -22,7 +24,12 @@ const target: PlatformTarget = {
2224
},
2325

2426
async startLibp2p(gossipLog, config) {
25-
throw new Error("Cannot start libp2p in the browser")
27+
let privateKey = config.privateKey
28+
if (privateKey === undefined) {
29+
privateKey = await getPrivateKey()
30+
}
31+
32+
return await getLibp2p(gossipLog, { ...config, privateKey })
2633
},
2734
}
2835

0 commit comments

Comments
 (0)