Skip to content

Commit 539c92f

Browse files
committed
feat: add light push v3 protocol detection and handling
1 parent b7bdecc commit 539c92f

1 file changed

Lines changed: 84 additions & 10 deletions

File tree

packages/core/src/lib/light_push/light_push.ts

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import {
33
type CoreProtocolResult,
44
type IEncoder,
55
type IMessage,
6+
isSuccess as isV3Success,
67
type Libp2p,
78
ProtocolError,
8-
type ThisOrThat
9+
type ThisOrThat,
10+
toProtocolError
911
} from "@waku/interfaces";
1012
import { PushResponse } from "@waku/proto";
1113
import { isMessageSizeUnderCap } from "@waku/utils";
@@ -16,13 +18,16 @@ import { pipe } from "it-pipe";
1618
import { Uint8ArrayList } from "uint8arraylist";
1719

1820
import { StreamManager } from "../stream_manager/index.js";
21+
import { selectOpenConnection } from "../stream_manager/utils.js";
1922

2023
import { PushRpc } from "./push_rpc.js";
2124
import { isRLNResponseError } from "./utils.js";
2225

2326
const log = new Logger("light-push");
2427

2528
export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
29+
export const LightPushCodecV3 = "/vac/waku/lightpush/3.0.0";
30+
export const LightPushCodecs = [LightPushCodecV3, LightPushCodec];
2631
export { PushResponse };
2732

2833
type PreparePushMessageResult = ThisOrThat<"query", PushRpc>;
@@ -34,11 +39,49 @@ export class LightPushCore {
3439
private readonly streamManager: StreamManager;
3540

3641
public readonly multicodec = LightPushCodec;
42+
public readonly multicodecs = LightPushCodecs;
3743

38-
public constructor(libp2p: Libp2p) {
44+
public constructor(private libp2p: Libp2p) {
3945
this.streamManager = new StreamManager(LightPushCodec, libp2p.components);
4046
}
4147

48+
private async getProtocolStream(
49+
peerId: PeerId
50+
): Promise<{ stream: Stream; protocol: string }> {
51+
const peer = await this.libp2p.peerStore.get(peerId);
52+
const protocols = peer.protocols;
53+
54+
const supportsV3 = protocols.includes(LightPushCodecV3);
55+
const supportsV2 = protocols.includes(LightPushCodec);
56+
57+
if (!supportsV2 && !supportsV3) {
58+
throw new Error("Peer does not support any Light Push protocol");
59+
}
60+
61+
const protocol = supportsV3 ? LightPushCodecV3 : LightPushCodec;
62+
63+
let stream: Stream;
64+
try {
65+
const connections = this.libp2p.getConnections(peerId);
66+
const connection = selectOpenConnection(connections);
67+
68+
if (!connection) {
69+
throw new Error("No open connection to peer");
70+
}
71+
72+
stream = await connection.newStream(protocol);
73+
} catch (error) {
74+
if (supportsV3 && supportsV2) {
75+
log.warn("Failed to create v3 stream, falling back to v2", error);
76+
stream = await this.streamManager.getStream(peerId);
77+
return { stream, protocol: LightPushCodec };
78+
}
79+
throw error;
80+
}
81+
82+
return { stream, protocol };
83+
}
84+
4285
private async preparePushMessage(
4386
encoder: IEncoder,
4487
message: IMessage
@@ -96,17 +139,26 @@ export class LightPushCore {
96139
}
97140

98141
let stream: Stream;
142+
let protocol: string;
99143
try {
100-
stream = await this.streamManager.getStream(peerId);
144+
const result = await this.getProtocolStream(peerId);
145+
stream = result.stream;
146+
protocol = result.protocol;
147+
log.info(`Using protocol ${protocol} for peer ${peerId.toString()}`);
101148
} catch (error) {
102149
log.error("Failed to get stream", error);
103-
return {
104-
success: null,
105-
failure: {
106-
error: ProtocolError.NO_STREAM_AVAILABLE,
107-
peerId: peerId
108-
}
109-
};
150+
try {
151+
stream = await this.streamManager.getStream(peerId);
152+
protocol = LightPushCodec;
153+
} catch (fallbackError) {
154+
return {
155+
success: null,
156+
failure: {
157+
error: ProtocolError.NO_STREAM_AVAILABLE,
158+
peerId: peerId
159+
}
160+
};
161+
}
110162
}
111163

112164
let res: Uint8ArrayList[] | undefined;
@@ -160,6 +212,28 @@ export class LightPushCore {
160212
};
161213
}
162214

215+
if (protocol === LightPushCodecV3 && response.statusCode !== undefined) {
216+
if (!isV3Success(response.statusCode)) {
217+
const error = toProtocolError(response.statusCode);
218+
log.error(
219+
`Remote peer rejected with v3 status code ${response.statusCode}: ${response.statusDesc || response.info}`
220+
);
221+
return {
222+
success: null,
223+
failure: {
224+
error,
225+
peerId: peerId
226+
}
227+
};
228+
}
229+
230+
if (response.relayPeerCount !== undefined) {
231+
log.info(`Message relayed to ${response.relayPeerCount} peers`);
232+
}
233+
234+
return { success: peerId, failure: null };
235+
}
236+
163237
if (isRLNResponseError(response.info)) {
164238
log.error("Remote peer fault: RLN generation");
165239
return {

0 commit comments

Comments
 (0)