lamport timestamp remains close to current time

This commit is contained in:
fryorcraken 2025-10-01 21:25:58 +10:00
parent 5dd9f77ce3
commit 166f086faa
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
3 changed files with 82 additions and 17 deletions

View File

@ -721,7 +721,7 @@ describe("Reliable Channel", () => {
"differentChannel",
senderId,
[],
1,
1n,
undefined,
utf8ToBytes("different channel")
);
@ -731,7 +731,7 @@ describe("Reliable Channel", () => {
channelId,
senderId,
[],
2,
2n,
undefined,
undefined
);
@ -741,7 +741,7 @@ describe("Reliable Channel", () => {
channelId,
senderId,
[],
3,
3n,
undefined,
utf8ToBytes("after sync")
);
@ -824,7 +824,7 @@ describe("Reliable Channel", () => {
channelId,
senderId,
[{ messageId: "previous-msg-id" }],
1,
1n,
undefined,
utf8ToBytes("content message")
);
@ -834,7 +834,7 @@ describe("Reliable Channel", () => {
channelId,
senderId,
[],
2,
2n,
undefined,
utf8ToBytes("after content")
);
@ -905,7 +905,7 @@ describe("Reliable Channel", () => {
"differentChannel1",
senderId,
[],
1,
1n,
undefined,
utf8ToBytes("different 1")
);
@ -915,7 +915,7 @@ describe("Reliable Channel", () => {
"differentChannel2",
senderId,
[],
2,
2n,
undefined,
utf8ToBytes("different 2")
);
@ -925,7 +925,7 @@ describe("Reliable Channel", () => {
"differentChannel3",
senderId,
[],
3,
3n,
undefined,
utf8ToBytes("different 3")
);
@ -1041,7 +1041,7 @@ describe("Reliable Channel", () => {
"differentChannel",
"sender",
[],
1,
1n,
undefined,
utf8ToBytes("content")
);
@ -1060,7 +1060,7 @@ describe("Reliable Channel", () => {
"testChannel",
"sender",
[],
1,
1n,
undefined,
undefined
);
@ -1079,7 +1079,7 @@ describe("Reliable Channel", () => {
"testChannel",
"sender",
[],
1,
1n,
undefined,
utf8ToBytes("content")
);
@ -1098,7 +1098,7 @@ describe("Reliable Channel", () => {
"testChannel",
"sender",
[{ messageId: "previous-msg-id" }],
1,
1n,
undefined,
utf8ToBytes("content")
);
@ -1117,7 +1117,7 @@ describe("Reliable Channel", () => {
"testChannel",
"sender",
[{ messageId: "previous-msg-id" }],
1,
1n,
undefined,
undefined
);

View File

@ -0,0 +1,56 @@
import { expect } from "chai";
import { lamportTimestampIncrement } from "./message_channel.js";
describe("lamportTimestampIncrement", () => {
it("should increment timestamp by 1 when current time is not greater", () => {
const futureTimestamp = BigInt(Date.now()) + 1000n;
const result = lamportTimestampIncrement(futureTimestamp);
expect(result).to.equal(futureTimestamp + 1n);
});
it("should use current time when it's greater than incremented timestamp", () => {
const pastTimestamp = BigInt(Date.now()) - 1000n;
const result = lamportTimestampIncrement(pastTimestamp);
const now = BigInt(Date.now());
// Result should be at least as large as now (within small tolerance for test execution time)
expect(result >= now - 10n).to.be.true;
expect(result <= now + 10n).to.be.true;
});
it("should handle timestamp equal to current time", () => {
const currentTimestamp = BigInt(Date.now());
const result = lamportTimestampIncrement(currentTimestamp);
// Should increment by 1 since now is likely not greater than current + 1
expect(result >= currentTimestamp + 1n).to.be.true;
});
it("should ensure monotonic increase", () => {
let timestamp = BigInt(Date.now()) + 5000n;
const results: bigint[] = [];
for (let i = 0; i < 5; i++) {
timestamp = lamportTimestampIncrement(timestamp);
results.push(timestamp);
}
// Verify all timestamps are strictly increasing
for (let i = 1; i < results.length; i++) {
expect(results[i] > results[i - 1]).to.be.true;
}
});
it("should handle very large timestamps", () => {
const largeTimestamp = BigInt(Number.MAX_SAFE_INTEGER) * 1000n;
const result = lamportTimestampIncrement(largeTimestamp);
expect(result).to.equal(largeTimestamp + 1n);
});
it("should jump to current time when timestamp is far in the past", () => {
const veryOldTimestamp = 1000n; // Very old timestamp (1 second after epoch)
const result = lamportTimestampIncrement(veryOldTimestamp);
const now = BigInt(Date.now());
expect(result >= now - 10n).to.be.true;
expect(result <= now + 10n).to.be.true;
});
});

View File

@ -95,8 +95,8 @@ export class MessageChannel extends TypedEventEmitter<MessageChannelEvents> {
super();
this.channelId = channelId;
this.senderId = senderId;
// Initialize channel lamport timestamp to current time in seconds.
this.lamportTimestamp = BigInt(Math.floor(Date.now() / 1000));
// Initialize channel lamport timestamp to current time in milliseconds.
this.lamportTimestamp = BigInt(Date.now());
this.filter = new DefaultBloomFilter(DEFAULT_BLOOM_FILTER_OPTIONS);
this.outgoingBuffer = [];
this.possibleAcks = new Map();
@ -368,7 +368,7 @@ export class MessageChannel extends TypedEventEmitter<MessageChannelEvents> {
public async pushOutgoingSyncMessage(
callback?: (message: SyncMessage) => Promise<boolean>
): Promise<boolean> {
this.lamportTimestamp = this.lamportTimestamp + 1n;
this.lamportTimestamp = lamportTimestampIncrement(this.lamportTimestamp);
const message = new SyncMessage(
// does not need to be secure randomness
`sync-${Math.random().toString(36).substring(2)}`,
@ -525,7 +525,7 @@ export class MessageChannel extends TypedEventEmitter<MessageChannelEvents> {
retrievalHint?: Uint8Array;
}>
): Promise<void> {
this.lamportTimestamp = this.lamportTimestamp + 1n;
this.lamportTimestamp = lamportTimestampIncrement(this.lamportTimestamp);
const messageId = MessageChannel.getMessageId(payload);
@ -723,3 +723,12 @@ export class MessageChannel extends TypedEventEmitter<MessageChannelEvents> {
});
}
}
export function lamportTimestampIncrement(lamportTimestamp: bigint): bigint {
const now = BigInt(Date.now());
lamportTimestamp++;
if (now > lamportTimestamp) {
return now;
}
return lamportTimestamp;
}