mirror of
https://github.com/logos-messaging/logos-delivery-js.git
synced 2026-03-13 13:13:08 +00:00
* feat: implement LightPush v3 protocol support Add comprehensive LightPush v3 protocol implementation with: Core Features: - LightPush v3 protocol codec and multicodec detection - Status code-based error handling and validation - Protocol version inference and compatibility layers - Enhanced error types with detailed failure information Protocol Support: - Automatic v3/v2 protocol negotiation and fallback - Status code mapping to LightPush error types - Protocol version tracking in SDK results - Mixed protocol environment support Testing Infrastructure: - Comprehensive v3 error code handling tests - Mock functions for v3/v2 response scenarios - Protocol version detection and validation tests - Backward compatibility verification Implementation Details: - Clean separation between v2 and v3 response handling - Type-safe status code validation with isSuccess helper - Enhanced failure reporting with protocol version context - Proper error propagation through SDK layers This implementation maintains full backward compatibility with v2 while providing enhanced functionality for v3 protocol features. * feat: handle both light push protocols * fix: unsubscribe test * feat: consolidate lpv2/v3 types * feat(tests): bump nwaku to 0.36.0 * fix: remove extraneous exports * fix: add delay to tests * fix: remove protocol result types * feat: consolidate light push codec branching * fix: revert nwaku image * fix: remove multicodec * fix: remove protocolversion * feat: simplify v2/v3 branching logic to use two stream managers * fix: remove unused utils * fix: remove comments * fix: revert store test * fix: cleanup lightpush sdk * fix: remove unused util * fix: remove unused exports * fix: rename file from public to protocol_handler * fix: use proper type for sdk result * fix: update return types in filter * fix: rebase against latest master * fix: use both lightpush codecs when waiting for peer * fix: handle both lp codecs * fix: remove unused code * feat: use array for multicodec fields * fix: add timestamp if missing in v3 rpc * fix: resolve on either lp codec when waiting for peer * fix: remove unused util * fix: remove unnecessary abstraction * feat: accept nwaku docker image as arg, test lp backwards compat * fix: revert filter error * feat: add legacy flag to enable lightpushv2 only * Revert "feat: accept nwaku docker image as arg, test lp backwards compat" This reverts commit 857e12cbc73305e5c51abd057665bd34708b2737. * fix: remove unused test * feat: improve lp3 (#2597) * improve light push core * move back to singualar multicodec property, enable array prop only for light push * implement v2/v3 interop e2e test, re-add useLegacy flag, ensure e2e runs for v2 and v3 * fix v2 v3 condition * generate message package earlier * add log, fix condition --------- Co-authored-by: Sasha <118575614+weboko@users.noreply.github.com> Co-authored-by: Sasha <oleksandr@status.im>
264 lines
9.0 KiB
TypeScript
264 lines
9.0 KiB
TypeScript
import { createEncoder } from "@waku/core";
|
|
import { IRateLimitProof, LightNode, LightPushError } from "@waku/interfaces";
|
|
import { utf8ToBytes } from "@waku/sdk";
|
|
import { expect } from "chai";
|
|
|
|
import {
|
|
afterEachCustom,
|
|
beforeEachCustom,
|
|
generateRandomUint8Array,
|
|
runMultipleNodes,
|
|
ServiceNodesFleet,
|
|
teardownNodesWithRedundancy,
|
|
TEST_STRING
|
|
} from "../../src/index.js";
|
|
|
|
import {
|
|
messagePayload,
|
|
messageText,
|
|
TestContentTopic,
|
|
TestEncoder,
|
|
TestRoutingInfo
|
|
} from "./utils.js";
|
|
|
|
const runTests = (strictNodeCheck: boolean, useLegacy: boolean): void => {
|
|
const numServiceNodes = 2;
|
|
describe(`Waku Light Push (legacy=${useLegacy ? "v2" : "v3"}): Multiple Nodes: Strict Check: ${strictNodeCheck}`, function () {
|
|
// Set the timeout for all tests in this suite. Can be overwritten at test level
|
|
this.timeout(15000);
|
|
let waku: LightNode;
|
|
let serviceNodes: ServiceNodesFleet;
|
|
|
|
beforeEachCustom(this, async () => {
|
|
[serviceNodes, waku] = await runMultipleNodes(
|
|
this.ctx,
|
|
TestRoutingInfo,
|
|
{ lightpush: true, filter: true },
|
|
strictNodeCheck,
|
|
numServiceNodes,
|
|
true,
|
|
{ lightPush: { useLegacy } }
|
|
);
|
|
});
|
|
|
|
afterEachCustom(this, async () => {
|
|
await teardownNodesWithRedundancy(serviceNodes, waku);
|
|
});
|
|
|
|
TEST_STRING.forEach((testItem) => {
|
|
it(`Push message with ${testItem.description} payload`, async function () {
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: utf8ToBytes(testItem.value)
|
|
});
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
true
|
|
);
|
|
serviceNodes.messageCollector.verifyReceivedMessage(0, {
|
|
expectedMessageText: testItem.value,
|
|
expectedContentTopic: TestContentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
});
|
|
});
|
|
|
|
// TODO: skipped till https://github.com/waku-org/nwaku/issues/3369 resolved
|
|
it.skip("Push 30 different messages", async function () {
|
|
const generateMessageText = (index: number): string => `M${index}`;
|
|
|
|
for (let i = 0; i < 30; i++) {
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: utf8ToBytes(generateMessageText(i))
|
|
});
|
|
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
}
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(30)).to.eq(
|
|
true
|
|
);
|
|
|
|
for (let i = 0; i < 30; i++) {
|
|
serviceNodes.messageCollector.verifyReceivedMessage(i, {
|
|
expectedMessageText: generateMessageText(i),
|
|
expectedContentTopic: TestContentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
}
|
|
});
|
|
|
|
it("Throws when trying to push message with empty payload", async function () {
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: new Uint8Array()
|
|
});
|
|
|
|
expect(pushResponse.successes.length).to.eq(0);
|
|
|
|
expect(pushResponse.failures?.map((failure) => failure.error)).to.include(
|
|
LightPushError.EMPTY_PAYLOAD
|
|
);
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
false
|
|
);
|
|
});
|
|
|
|
TEST_STRING.forEach((testItem) => {
|
|
if (!testItem.invalidContentTopic) {
|
|
it(`Push message with content topic containing ${testItem.description}`, async function () {
|
|
const contentTopic = `/test/1/${testItem.value}/proto`;
|
|
const customEncoder = waku.createEncoder({
|
|
contentTopic
|
|
});
|
|
const pushResponse = await waku.lightPush.send(
|
|
customEncoder,
|
|
messagePayload
|
|
);
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
|
|
expect(
|
|
await serviceNodes.messageCollector.waitForMessages(1, {
|
|
contentTopic
|
|
})
|
|
).to.eq(true);
|
|
serviceNodes.messageCollector.verifyReceivedMessage(0, {
|
|
expectedMessageText: messageText,
|
|
expectedContentTopic: contentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
it("Push message with meta", async function () {
|
|
const customTestEncoder = createEncoder({
|
|
contentTopic: TestContentTopic,
|
|
metaSetter: () => new Uint8Array(10),
|
|
routingInfo: TestRoutingInfo
|
|
});
|
|
|
|
const pushResponse = await waku.lightPush.send(
|
|
customTestEncoder,
|
|
messagePayload
|
|
);
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
true
|
|
);
|
|
serviceNodes.messageCollector.verifyReceivedMessage(0, {
|
|
expectedMessageText: messageText,
|
|
expectedContentTopic: TestContentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
});
|
|
|
|
it("Fails to push message with large meta", async function () {
|
|
const customTestEncoder = createEncoder({
|
|
contentTopic: TestContentTopic,
|
|
routingInfo: TestRoutingInfo,
|
|
metaSetter: () => new Uint8Array(105024) // see the note below ***
|
|
});
|
|
|
|
// *** note: this test used 10 ** 6 when `nwaku` node had MaxWakuMessageSize == 1MiB ( 1*2^20 .)
|
|
// `nwaku` establishes the max lightpush msg size as `const MaxRpcSize* = MaxWakuMessageSize + 64 * 1024`
|
|
// see: https://github.com/waku-org/nwaku/blob/07beea02095035f4f4c234ec2dec1f365e6955b8/waku/waku_lightpush/rpc_codec.nim#L15
|
|
// In the PR https://github.com/waku-org/nwaku/pull/2298 we reduced the MaxWakuMessageSize
|
|
// from 1MiB to 150KiB. Therefore, the 105024 number comes from subtracting ( 1*2^20 - 150*2^10 )
|
|
// to the original 10^6 that this test had when MaxWakuMessageSize == 1*2^20
|
|
|
|
const pushResponse = await waku.lightPush.send(
|
|
customTestEncoder,
|
|
messagePayload
|
|
);
|
|
|
|
expect(pushResponse.successes.length).to.eq(0);
|
|
expect(pushResponse.failures?.map((failure) => failure.error)).to.include(
|
|
LightPushError.REMOTE_PEER_REJECTED
|
|
);
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
false
|
|
);
|
|
});
|
|
|
|
it("Push message with rate limit", async function () {
|
|
const rateLimitProof: IRateLimitProof = {
|
|
proof: utf8ToBytes("proofData"),
|
|
merkleRoot: utf8ToBytes("merkleRootData"),
|
|
epoch: utf8ToBytes("epochData"),
|
|
shareX: utf8ToBytes("shareXData"),
|
|
shareY: utf8ToBytes("shareYData"),
|
|
nullifier: utf8ToBytes("nullifierData"),
|
|
rlnIdentifier: utf8ToBytes("rlnIdentifierData")
|
|
};
|
|
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: utf8ToBytes(messageText),
|
|
rateLimitProof: rateLimitProof
|
|
});
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
true
|
|
);
|
|
serviceNodes.messageCollector.verifyReceivedMessage(0, {
|
|
expectedMessageText: messageText,
|
|
expectedContentTopic: TestContentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
});
|
|
|
|
[
|
|
Date.now() - 3600000 * 24 * 356,
|
|
Date.now() - 3600000,
|
|
Date.now() + 3600000
|
|
].forEach((testItem) => {
|
|
it(`Push message with custom timestamp: ${testItem}`, async function () {
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: utf8ToBytes(messageText),
|
|
timestamp: new Date(testItem)
|
|
});
|
|
expect(pushResponse.successes.length).to.eq(numServiceNodes);
|
|
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
true
|
|
);
|
|
serviceNodes.messageCollector.verifyReceivedMessage(0, {
|
|
expectedMessageText: messageText,
|
|
expectedTimestamp: testItem,
|
|
expectedContentTopic: TestContentTopic,
|
|
expectedPubsubTopic: TestRoutingInfo.pubsubTopic
|
|
});
|
|
});
|
|
});
|
|
|
|
it("Push message equal or less that 1MB", async function () {
|
|
const bigPayload = generateRandomUint8Array(65536);
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: bigPayload
|
|
});
|
|
expect(pushResponse.successes.length).to.greaterThan(0);
|
|
});
|
|
|
|
it("Fails to push message bigger that 1MB", async function () {
|
|
const MB = 1024 ** 2;
|
|
|
|
const pushResponse = await waku.lightPush.send(TestEncoder, {
|
|
payload: generateRandomUint8Array(MB + 65536)
|
|
});
|
|
expect(pushResponse.successes.length).to.eq(0);
|
|
expect(pushResponse.failures?.map((failure) => failure.error)).to.include(
|
|
LightPushError.SIZE_TOO_BIG
|
|
);
|
|
expect(await serviceNodes.messageCollector.waitForMessages(1)).to.eq(
|
|
false
|
|
);
|
|
});
|
|
});
|
|
};
|
|
|
|
[true, false].forEach((strictNodeCheck) => {
|
|
[true, false].forEach((legacy) => runTests(strictNodeCheck, legacy));
|
|
});
|