@peerbit/shared-log 13.2.32 → 13.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,4 @@
1
- import { serialize } from "@dao-xyz/borsh";
2
- import { type PublicSignKey, randomBytes, sha256Sync } from "@peerbit/crypto";
1
+ import { type PublicSignKey, randomBytes } from "@peerbit/crypto";
3
2
  import { logger as loggerFn } from "@peerbit/logger";
4
3
  import type { RPC } from "@peerbit/rpc";
5
4
  import {
@@ -8,7 +7,7 @@ import {
8
7
  } from "@peerbit/stream-interface";
9
8
  import type { TransportMessage } from "./message.js";
10
9
  import type { ReplicationRangeIndexable } from "./ranges.js";
11
- import { concat, fromString } from "uint8arrays";
10
+ import { deriveReplicationInfoV2ReceiverBinding } from "./replication-info-v2-binding.js";
12
11
  import {
13
12
  AddedReplicationInfoV2Message,
14
13
  AddedReplicationSegmentMessage,
@@ -22,46 +21,8 @@ import {
22
21
  const logger = loggerFn("peerbit:shared-log:replication-info-v2-send");
23
22
 
24
23
  const MAX_U64 = (1n << 64n) - 1n;
25
- const RECEIVER_BINDING_DOMAIN = fromString(
26
- "peerbit/shared-log/replication-info-v2/receiver-binding/v1",
27
- );
28
-
29
- const lengthPrefixed = (bytes: Uint8Array): Uint8Array => {
30
- const length = new Uint8Array(4);
31
- new DataView(length.buffer).setUint32(0, bytes.byteLength, true);
32
- return concat([length, bytes]);
33
- };
34
-
35
- const u64LittleEndian = (value: bigint): Uint8Array => {
36
- const bytes = new Uint8Array(8);
37
- new DataView(bytes.buffer).setBigUint64(0, value, true);
38
- return bytes;
39
- };
40
24
 
41
- /**
42
- * Derive the token echoed by V2 data frames. Delivery recipients are unsigned,
43
- * so the receiver's nonce alone is not a destination binding. Folding both
44
- * authenticated identities and signed transport sessions into the 32-byte
45
- * field prevents a copied request nonce from creating an interchangeable
46
- * stream for another receiver.
47
- */
48
- export const deriveReplicationInfoV2ReceiverBinding = (properties: {
49
- receiverChallenge: Uint8Array;
50
- receiver: PublicSignKey;
51
- receiverTransportSession: bigint;
52
- sender: PublicSignKey;
53
- senderTransportSession: bigint;
54
- }): Uint8Array =>
55
- sha256Sync(
56
- concat([
57
- lengthPrefixed(RECEIVER_BINDING_DOMAIN),
58
- lengthPrefixed(properties.receiverChallenge),
59
- lengthPrefixed(serialize(properties.receiver)),
60
- u64LittleEndian(properties.receiverTransportSession),
61
- lengthPrefixed(serialize(properties.sender)),
62
- u64LittleEndian(properties.senderTransportSession),
63
- ]),
64
- );
25
+ export { deriveReplicationInfoV2ReceiverBinding } from "./replication-info-v2-binding.js";
65
26
 
66
27
  export type LegacyReplicationInfoMessage =
67
28
  | AllReplicatingSegmentsMessage
@@ -78,6 +39,7 @@ export type ReplicationInfoV2SendState = {
78
39
  peerSession: object;
79
40
  receiverTransportSession: bigint;
80
41
  senderTransportSession: bigint;
42
+ capabilityTimestamp: bigint;
81
43
  lastRequestTimestamp: bigint;
82
44
  receiverRequestChallenge: Uint8Array;
83
45
  receiverChallenge: Uint8Array;
@@ -218,8 +180,8 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
218
180
  /**
219
181
  * Accept a signed receiver request. An exact newer retry asks for another
220
182
  * full snapshot without resetting the epoch/sequence. A different challenge
221
- * cannot replace the first binding within one PeerSession; this prevents a
222
- * signed request flood from spawning unbounded orphan snapshot reads.
183
+ * can replace the binding only after a strictly newer signed capability;
184
+ * retiring work is drained before the replacement can start.
223
185
  */
224
186
  acceptRequest(
225
187
  request: RequestReplicationInfoV2Message,
@@ -227,6 +189,7 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
227
189
  from: PublicSignKey;
228
190
  peerSession: object;
229
191
  receiverTransportSession: bigint;
192
+ capabilityTimestamp: bigint;
230
193
  requestTimestamp: bigint;
231
194
  },
232
195
  ): boolean {
@@ -275,12 +238,20 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
275
238
  return false;
276
239
  }
277
240
  previous.lastRequestTimestamp = properties.requestTimestamp;
241
+ previous.capabilityTimestamp = properties.capabilityTimestamp;
278
242
  previous.suspended = false;
279
243
  this.enqueueState(previous, { kind: "snapshot" });
280
244
  return true;
281
245
  }
282
246
 
283
- return false;
247
+ if (properties.capabilityTimestamp <= previous.capabilityTimestamp) {
248
+ return false;
249
+ }
250
+ this.clearState(previous);
251
+ previous = undefined;
252
+ if (this._retiringWorkersByPeer.has(peerHash)) {
253
+ return false;
254
+ }
284
255
  }
285
256
 
286
257
  const ownershipLifecycleController =
@@ -291,6 +262,7 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
291
262
  peerSession: properties.peerSession,
292
263
  receiverTransportSession: properties.receiverTransportSession,
293
264
  senderTransportSession,
265
+ capabilityTimestamp: properties.capabilityTimestamp,
294
266
  lastRequestTimestamp: properties.requestTimestamp,
295
267
  receiverRequestChallenge: request.receiverChallenge.slice(),
296
268
  receiverChallenge: deriveReplicationInfoV2ReceiverBinding({