fryorcraken 4d5c152f5b
feat: introduce reliable channels (#2526)
* SDS: pushOutgoingMessage is actually sync

* SDS: ensure that `ContentMessage` class is stored in local history with `valueOf` method

* feat: introduce reliable channels

Easy to use Scalable Data Sync (SDS, e2e reliability) wrapper, that includes:
- store queries upon connection to store nodes
- store queries to retrieve missing messages

* remove `channel` prefix

* attempt to improve performance when processing a lot of incoming messages

* test: split test file

* use index.ts for re-export only.

* improve if condition

* use getter for isStarted

* waku node already auto-start

* rename send

* fix lightPush.send type post rebase

* test: remove extra console.log

* SDS: emit messages as missing as soon as they are received

* make configurable elapse time for task process

* typo

* use string instead of enum for event types

* ReliableChannel.send returns the message id
2025-09-09 12:43:48 +10:00

111 lines
2.6 KiB
TypeScript

import { utf8ToBytes } from "@waku/utils/bytes";
import { expect } from "chai";
import { DefaultBloomFilter } from "../bloom_filter/bloom.js";
import { ContentMessage, Message } from "./message.js";
import { DEFAULT_BLOOM_FILTER_OPTIONS } from "./message_channel.js";
describe("Message serialization", () => {
it("Bloom filter", () => {
const messageId = "first";
const bloomFilter = new DefaultBloomFilter(DEFAULT_BLOOM_FILTER_OPTIONS);
bloomFilter.insert(messageId);
const message = new Message(
"123",
"my-channel",
"me",
[],
0,
bloomFilter.toBytes(),
undefined
);
const bytes = message.encode();
const decMessage = Message.decode(bytes);
const decBloomFilter = DefaultBloomFilter.fromBytes(
decMessage!.bloomFilter!,
DEFAULT_BLOOM_FILTER_OPTIONS
);
expect(decBloomFilter.lookup(messageId)).to.be.true;
});
it("Retrieval Hint", () => {
const depMessageId = "dependency";
const depRetrievalHint = utf8ToBytes("dependency");
const message = new Message(
"123",
"my-channel",
"me",
[{ messageId: depMessageId, retrievalHint: depRetrievalHint }],
0,
undefined,
undefined
);
const bytes = message.encode();
const decMessage = Message.decode(bytes);
expect(decMessage!.causalHistory).to.deep.equal([
{ messageId: depMessageId, retrievalHint: depRetrievalHint }
]);
});
});
describe("ContentMessage comparison with < operator", () => {
it("should sort by lamportTimestamp when timestamps differ", () => {
const msgA = new ContentMessage(
"zzz", // Higher messageId
"channel",
"sender",
[],
100, // Lower timestamp
undefined,
new Uint8Array([1])
);
const msgB = new ContentMessage(
"aaa", // Lower messageId
"channel",
"sender",
[],
200, // Higher timestamp
undefined,
new Uint8Array([2])
);
// Despite msgA having higher messageId, it should be < msgB due to lower timestamp
expect(msgA < msgB).to.be.true;
expect(msgB < msgA).to.be.false;
});
it("should sort by messageId when timestamps are equal", () => {
const msgA = new ContentMessage(
"aaa", // Lower messageId
"channel",
"sender",
[],
100, // Same timestamp
undefined,
new Uint8Array([1])
);
const msgB = new ContentMessage(
"zzz", // Higher messageId
"channel",
"sender",
[],
100, // Same timestamp
undefined,
new Uint8Array([2])
);
expect(msgA < msgB).to.be.true;
expect(msgB < msgA).to.be.false;
});
});